我正在尝试将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 Time18: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.TimestampZonedDateTime和数据库存储都在UTC中。



当您确实需要转移到某些地区的wall-clock time时,请应用时区。

ZoneId zoneId = ZoneId.of( "America/Chicago" );  // Or "America/New_York" and so on.
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

10-06 09:12
查看更多