我正在尝试将ZonedDateTime转换为日期。看起来像在转换中,它会释放时区并获取我的本地时间。
System.out.println("zoneDate1::::::::::"+ZonedDateTime.now(ZoneId.of("America/Chicago")));
System.out.println("zoneDate1:Date::::::::::"+Date.from(ZonedDateTime.now(ZoneId.of("America/Chicago")).toInstant()));
以上输出如下:
zoneDate1::::::::::2016-04-15T17:35:06.357-05:00[America/Chicago]
zoneDate1:Date::::::::::Fri Apr 15 18:35:06 EDT 2016
这是因为这是日期类型吗?我将如何进行这种转换并节省分区时间?
最佳答案
问题是什么?您期望什么?我没有任何不当行为。
您的java.time类型(ZonedDateTime
)被分配了America/Chicago
时区。
您的JVM显然已分配了与北美东海岸有关的时区,线索是在字符串输出中看到的EDT
值。生成日期时间值的文本表示形式时,java.util.Date上的toString
方法将应用JVM的当前默认时区。设计得很差,此行为试图提供帮助,但实际上令人困惑,因为您实际上无法在java.util.Date对象上获取或设置此时区。
无论如何,北美东海岸(例如America/New_York
时区)比America/Chicago
早一个小时。因此,您看到的是芝加哥的17:xx:xx
时间,Eastern Daylight Saving Time的18:xx:xx
时间。这些值是正确的。
调查旧的日期时间类的行为时,应调用java.util.TimeZone.getDefault()
。
java.time
更大的问题是,您甚至在使用这些旧的日期时间类,例如java.util.Date/.Calendar。它们的设计不当,令人困惑且麻烦。完全避免使用这些旧类。它们已被Java 8和后来的java.time框架取代。
另外,请避免使用3-4个字母区域的缩写,例如EDT
。这些既不是标准化的也不是唯一的。在大陆/地区格式中使用proper time zone names。Instant
要捕获java.time中的当前日期时间,只需使用Instant
。此类捕获UTC中时间轴上的时刻。在UTC中完成大部分工作。除非用户期望在用户界面中显示时,否则不需要时区。
Instant now = Instant.now();
数据库
要发送到数据库,首先要确保已将表中的列定义为SQL标准
TIMESTAMP WITH TIME ZONE
的一行。顺便说一下,数据库中对日期时间类型的支持各不相同,其中一些比其他的要好得多。希望有一天会更新JDBC驱动程序,以直接处理java.time类型。在此之前,在向数据库传输数据或从数据库传输数据时,我们必须将其转换为java.sql类型。旧的java.sql类具有促进这些转换的新方法。
java.sql.Timestamp
对于像
Instant
这样的日期时间值,我们需要java.sql.Timestamp
类及其from( Instant )
方法。java.sql.Timestamp ts = java.sql.Timestamp.from( now );
避免在
java.sql.Timestamp
中工作,因为Instant
是早期Java日期时间类设计不佳的烂摊子的一部分。仅将它们用于数据库传输,然后立即转换到java.time。Instant instant = ts.toInstant();
如此简单,不涉及任何时区或从UTC偏移。
java.sql.Timestamp
,ZonedDateTime
和数据库存储都在UTC中。当您确实需要转移到某些地区的wall-clock time时,请应用时区。
ZoneId zoneId = ZoneId.of( "America/Chicago" ); // Or "America/New_York" and so on.
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );