ZonedDateTime 和 OffsetDateTime 之间有什么区别?
我已经阅读了文档,但我仍然无法了解何时应该使用其中一个:
根据文档,在将日期写入数据库时应该使用,但我不明白为什么。OffsetDateTime
我已经阅读了文档,但我仍然无法了解何时应该使用其中一个:
根据文档,在将日期写入数据库时应该使用,但我不明白为什么。OffsetDateTime
问:java 8 ZonedDateTime 和 OffsetDateTime 有什么区别?
Javadocs是这样说的:
“
OffsetDateTime
,ZonedDateTime
和Instant
都在时间线上存储一个瞬间,精度达到纳秒级。即时
是最简单的,只是代表瞬间。OffsetDateTime
将 UTC/Greenwich 的偏移量添加到即时,从而允许获取本地日期时间。ZonedDateTime
添加了完整的时区规则。
资料来源:https://docs.oracle.com/javase/8/docs/api/java/time/OffsetDateTime.html
因此,和 之间的区别在于后者包括涵盖夏令时调整和各种其他异常的规则。OffsetDateTime
ZonedDateTime
简单地说:
时区 = ( 偏移量 - 来自 UTC + 异常规则 )
问:根据文档,在将日期写入数据库时应该使用,但我不明白为什么。
OffsetDateTime
具有本地时间偏移量的日期始终表示相同的时间时刻,因此具有稳定的顺序。相比之下,在对相应时区规则进行调整的情况下,具有完整时区信息的日期的含义是不稳定的。(这些确实会发生;例如,对于将来的日期时间值。因此,如果您存储然后检索一个实现,则存在问题:ZonedDateTime
它可以存储计算的偏移量...然后,检索到的对象可能具有与 zone-id 的当前规则不一致的偏移量。
它可以丢弃计算的偏移量...然后,检索到的对象表示绝对/通用时间线中与存储点不同的点。
如果使用 Java 对象序列化,则 Java 9 实现将采用第一种方法。这可以说是处理这个问题的“更正确”的方法,但似乎没有记录在案。(JDBC 驱动程序和 ORM 绑定大概正在做出类似的决定,并希望能够正确做出决定。
但是,如果您正在编写手动存储日期/时间值的应用程序,或者依赖于 的应用程序,那么处理zone-id的复杂性是...可能是要避免的。因此,建议。java.sql.DateTime
请注意,其含义/顺序随时间变化不稳定的日期对于应用程序来说可能是个问题。由于对区域规则的更改是一种边缘情况,因此这些问题很容易在意想不到的时候出现。
建议的第二个(可能的)原因是,a的构造在某些方面是模棱两可的。例如,在“将时钟放回去”的时间段内,将本地时间和 zone-id 组合在一起可以为您提供两个不同的偏移量。意志总是选择一个而不是另一个...但这并不总是正确的选择。ZonedDateTime
ZonedDateTime
现在,对于以这种方式构造值的任何应用程序来说,这可能是一个问题。但是,从构建企业应用程序的人的角度来看,当(可能不正确的)值是持久的并在以后使用时,这是一个更大的问题。ZonedDateTime
ZonedDateTime
接受的答案给出了非常完整的解释,也许下面的代码示例可以为您提供简短明了的图片:
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
-5:00
-04:00