我从postgres获取带有时区值的时间戳,在java中,我将结果存储在timestamp变量中。但是日期和时间会有一些变化。我没有得到最初的价值。
表
CREATE TABLE log_fail
(
user_name character varying(99) NOT NULL,
date_time timestamp with time zone,
CONSTRAINT pk_log_failed_login PRIMARY KEY (user_name)
)
表数据
用户名=超人
日期时间=2016-12-12 10:06:39.582-08
sql
字符串uname=“超人”;
String sql1=“从日志中选择日期时间”登录失败,其中用户名=““uname””;
rs1 = conn.createStatement().executeQuery(sql1);
if (rs1.next())
{
Timestamp attempt_datetime = rs1.getTimestamp("date_time");
}
我正在得到的结果
尝试日期时间=2016-12-12 23:36:39.582
https://www.postgresql.org/docs/current/static/datatype-datetime.html
对于带时区的时间戳,内部存储的值总是以UTC(通用协调时间,传统上称为格林尼治标准时间,GMT)为单位。指定了明确时区的输入值将使用该时区的适当偏移量转换为UTC。如果输入字符串中没有说明时区,则假定它位于系统的TimeZone参数指示的时区,并使用时区的偏移量转换为UTC。
当输出带有时区值的时间戳时,它总是从UTC转换为当前时区,并在该时区中显示为本地时间
检查客户的时区:
select setting from pg_settings where name = 'TimeZone';
这将给你一个想法,为什么不同客户的时间不同
你没有给我们看你所有的代码,所以我们不能肯定地回答。但是经过一些推断,我有一个理论,三个偏移的理论。
以比UTC晚八小时的值开始→ <代码>2016-12-12 10:06:39.582-08
调整到UTC→ <代码>2016-12-12 18:06:39.582Z
调整到偏移量05:30
→ <代码>2016-12-12 23:36:39.582 05:30
笨拙的报告→ <代码>2016-12-12 23:36:39.582
感谢Laurenz Albe解决核心问题的答案;我只是在这里添加了一段冗长的叙述。
几个术语:
05:00
。大陆/地区
,如美国/蒙特利尔
。您输入的2016-12-12 10:06:39.582-08
代表了比UTC晚八小时的时刻,在北美西海岸的大部分地区都有使用。
您将该值提交给Postgres存储。你说的不准确,但我假设表中的列是带时区的时间戳类型。
在Postgres中,这种类型的意思是:“对于任何伴随的偏移量/区域信息,将传入值调整为UTC”。Postgres然后放弃附带的偏移量/区域信息。我重复一遍,Postgres不存储或记住偏移量/区域,不在任何日期时间类型中。带类型的和不带时区的
类型的时间戳
之间的区别在于,在不带中,任何附带的偏移量/区域信息都会被完全忽略,不会进行任何调整。
因此,当您向Postgres提交
2016-12-12 10:06:39.582-08
时,该值会自动调整为2016-12-12 18:06:39.582Z
。这里的Z
是祖鲁的缩写,意思是UTC。此外,Postgres并没有按字面意思存储这些字符串,而是使用自己的内部二进制存储格式。这些字符串是供我们人类在讨论中阅读的。
无论如何,回到UTC的调整。请注意时间是如何从
10
小时变为18
小时的,因为从UTC后8小时调整到UTC意味着增加8小时。
很好,存储这个值的工作已经完成了。我们在时间上记录了完全相同的时刻,
2016-12-12 10:06:39.582-08
和2016-12-12 18:06:39.582Z
都是非常相同的时刻,但通过两个不同的墙上时钟时间值的镜头看到。到目前为止,一切都是合理和明智的。
后来,您从Postgres数据库中检索了
2016-12-12 18:06:39.582Z
值。显然,您通过JDBC将数据提取到一个java.sql.Timestamp
对象中。这就是问题所在。这个类是与Java最早版本捆绑在一起的旧日期-时间类之一。虽然作为日期-时间处理的行业领先尝试值得称赞,但这些类被证明是令人困惑、麻烦和有缺陷的。尽可能避免它们。它们现在是遗产,被java.time类取代。
这些遗留的日期-时间类的许多问题之一是它们的
toString
方法的实现。在隐式应用JVM的当前时区时,这些toString
方法过于渴望取悦。这些给这么多Java程序员带来了无尽的困惑。添加这个问题作为这种困惑的另一个例子。
首先,让我们演示时区的隐式应用。首先在UTC中获取当前时刻,作为
Instant
。
Instant instant = Instant.now ();
查看JVM当前的默认时区及其偏移量。
ZoneId z = ZoneId.systemDefault (); // Get current default time zone of this JVM.
String offset = z.getRules ().getOffset ( instant ).toString (); // Extract the offset-from-UTC from our default time zone.
最后,制作一个
java。sql。Timestamp
查看其toString
方法的行为。
java.sql.Timestamp ts = new java.sql.Timestamp ( instant.toEpochMilli () );
转储到控制台。
System.out.println ( "instant.toString(): " + instant );
System.out.println ( "z.toString(): " + z );
System.out.println ( "offset.toString(): " + offset );
System.out.println ( "ts.toString(): " + ts );
瞬间toString():2016-12-13T23:06:22.635Z
z.toString():美国/洛杉矶
偏移。toString():-08:00
t.toString():2016-12-13 15:06:22.635
从这个输出中,我们可以看到,
时间戳
确实将我自己当前默认的-08:00
偏移量应用于UTC的内部值。更糟糕的是,该方法的输出忽略了其偏移量的任何指示,这让我们假设它是UTC,而实际上不是。更令人沮丧的是:这个“功能”完全没有文档记录!
现在我们已经看到了这个反功能的行为,我们可以回到问题中的示例数据。显然,结果数据是
2016-12-12 23:36:39.582
,没有任何偏移指示,正如我们刚才提到的。但是看看一天中的时间,23:36:39.582
与我们可能预期的UTC时间,18:06:39.582
。意外值比预期UTC值提前五个半小时,或05:30
。印度和斯里兰卡在Asia/Kolkata
等地区碰巧使用了05:30的偏移量。因此我们可以推断,这个问题的作者在JVM上运行她的代码,当前默认时区为
Asia/columbo
或Asia/Kolkata
偏移量为05:30
。
避免遗留的日期时间类。
使用java。改为上时间课。爪哇。时间类都有合理的
toString
方法,可以明智地使用标准ISO 8601文本格式,而不会出现任何意外的额外行为。
您的JDBC 4.2兼容驱动程序可以通过调用
准备声明::setObject
和ResultSet::getObject
来直接处理java.time类型。
myPreparedStatement.setObject( … , instant ) ;
…还有…
Instant instant = myResultSet.getObject( … ) ;
如果没有,回到使用java.sql类型,但尽可能简短。使用添加到旧类中的新转换方法。
myPreparedStatement.setTimestamp( … , java.sql.Timestamp.from( instant ) ) ;
…还有…
Instant instant = myResultSet.getTimestamp( … ).toInstant() ;
java.time框架构建在Java8和更高版本中。这些类取代了麻烦的旧的遗留日期-时间类,如
java.util.Date
,日历
,
Joda Time项目现在处于维护模式,建议迁移到java。时间课。
要了解更多信息,请参阅Oracle教程。并在Stack Overflow中搜索许多示例和解释。规范是JSR 310。
在哪里可以获得java。时间课?
Java SE 8和SE 9及更高版本
Three10-Extra项目通过附加类扩展java.time。该项目是未来可能添加到java.time.的试验场。您可以在这里找到一些有用的类,如
Interval
,YearZacks
,YearQuter
等。
问题是,Java代码运行的机器上的时区是Asia/Calcutta
,时间戳在转换为字符串时会转换为该时区。
您可以在这样的Java更改您的时区:
java.util.TimeZone.setDefault(java.util.TimeZone.getTimeZone("Europe/Vienna"));
问题内容: 全部, 我有一个带有称为时间戳记的列的MYSQL表。它的数据类型为“ 10/1/2009 3:25:08 PM”,“ 10/1/2009 3:30:05 PM”,“ 10/4/2009 3:40:01 PM”,等等.. 我想编写一个SQL查询来选择在两个日期之间出现的时间戳字段中的所有值。 userInput日期将没有时间部分。您能为此建议正确的MySQL查询语法吗?谢谢 问题答案:
返回我女巫是错误的。 但接下来的查询如下: 我看对日期
我需要将查询中的日期值转换为带有时区的时间戳,但目前我得到的时区区域(“欧洲/巴黎”)是EF使用的无效区域。 例如,在执行此操作时:
我正在尝试将日期插入我的PostgreSQL数据库。以下是我在java应用程序中解析日期的方式: 在我的PostgreSQL数据库中。我将其作为带有时区的。处理和插入它的理想方式是什么? 数据库期望的示例。
我将Datagrip用于PostgreSQL。我有一个带有时间戳格式的日期字段的表。我希望能够: 应用数学运算符减去1天 根据当前-130天的时间窗口对其进行筛选 不显示邮票的HH/MM/SS部分(2016-10-31) 当前开始查询: 第1行的子句导致: [42883]错误:运算符不存在:没有时区的时间戳-整数提示:没有与给定名称和参数类型匹配的运算符。您可能需要添加显式类型转换。职位:69 子