我已经阅读了文档,但是当我应该使用其中一个时,我仍然无法获得:
根据文档OffsetDateTime
应该在将日期写入数据库时使用,但我不明白为什么。
答案 0 :(得分:153)
问:java 8 ZonedDateTime和OffsetDateTime之间的区别是什么?
javadocs说:
"
OffsetDateTime
,ZonedDateTime
和Instant
都会在时间线上存储一个纳秒精度的瞬间。Instant
是最简单的,只是代表瞬间。OffsetDateTime
添加到UTC / Greenwich的偏移瞬间,这允许获得本地日期时间。ZonedDateTime
添加了完整的时区规则。"
来源:https://docs.oracle.com/javase/8/docs/api/java/time/OffsetDateTime.html
因此OffsetDateTime
和ZonedDateTime
之间的区别在于后者包括涵盖夏令时调整和各种其他异常的规则。
简单地说:
Time Zone =(Offset-From-UTC +规则异常)
问:根据文档
OffsetDateTime
应该在将日期写入数据库时使用,但我不明白为什么。
具有本地时间偏移的日期始终表示时间相同的时刻,因此具有稳定的排序。相比之下,面对对各个时区的规则进行调整,具有全时区信息的日期的含义是不稳定的。 (并且这些确实发生了;例如,对于将来的日期时间值。)因此,如果您存储然后检索ZonedDateTime
,则实现有问题:
它可以存储计算出的偏移量......然后检索到的对象的偏移量可能与zone-id的当前规则不一致。
它可以丢弃计算出的偏移量...然后检索到的对象代表绝对/通用时间轴中与存储的不同的点。
如果使用Java对象序列化,则Java 9实现采用第一种方法。这可以说是更正确的"处理这个的方法,但这似乎没有记录。 (JDBC驱动程序和ORM绑定可能会做出类似的决定,并且希望能够做到正确。)
但是如果您正在编写一个手动存储日期/时间值的应用程序,或者依赖于java.sql.DateTime
的应用程序,那么处理区域ID的复杂性是......可能需要避免的事情。因此建议。
请注意,对于应用程序,其含义/排序随时间不稳定的日期可能有问题。而且由于对区域规则的更改是一个边缘情况,因此问题很可能在意外时刻出现。
建议的第二个可能原因是ZonedDateTime
的构造在某些点上是模糊的。例如,在您将时钟放回"的时间段内,组合本地时间和区域ID可以为您提供两种不同的偏移。 ZonedDateTime
将始终选择一个......但这并不总是正确的选择。
现在,对于以这种方式构造ZonedDateTime
值的任何应用程序来说,这可能是一个问题。但是,从某人构建企业应用程序的角度来看,当(可能不正确的)ZonedDateTime
值持久存在并在以后使用时,这是一个更大的问题。
答案 1 :(得分:2)
接受的答案给出了非常完整的解释,也许下面的代码示例可以为您提供简短而清晰的图片:
Instant instant = Instant.now();
Clock clock = Clock.fixed(instant, ZoneId.of("America/New_York"));
OffsetDateTime offsetDateTime = OffsetDateTime.now(clock);
ZonedDateTime zonedDateTime = ZonedDateTime.now(clock);
System.out.println(offsetDateTime); // 2019-01-03T19:10:16.806-05:00
System.out.println(zonedDateTime); // 2019-01-03T19:10:16.806-05:00[America/New_York]
System.out.println();
OffsetDateTime offsetPlusSixMonths = offsetDateTime.plusMonths(6);
ZonedDateTime zonedDateTimePlusSixMonths = zonedDateTime.plusMonths(6);
System.out.println(offsetPlusSixMonths); // 2019-07-03T19:10:16.806-05:00
System.out.println(zonedDateTimePlusSixMonths); // 2019-07-03T19:10:16.806-04:00[America/New_York]
System.out.println(zonedDateTimePlusSixMonths.toEpochSecond() - offsetPlusSixMonths.toEpochSecond()); // -3600
System.out.println();
System.out.println(zonedDateTimePlusSixMonths.toLocalDateTime()); // 2019-07-03T19:10:16.806
System.out.println(offsetPlusSixMonths.toLocalDateTime()); // 2019-07-03T19:10:16.806
简而言之,仅当您想考虑夏令时才使用 ZonedDateTime
,通常会有一个小时的差异,如您在上面的示例中看到的,ZonedDateTime
的偏移量从 {{ 1}} 到 -5:00
,在大多数情况下,您的业务逻辑最终可能会出现错误。
(来自 https://www.youtube.com/watch?v=nEQhx9hGutQ 的代码副本)