【发布时间】:2015-05-14 10:08:40
【问题描述】:
我已经阅读了文档,但我仍然不知道什么时候应该使用其中一个:
根据文档OffsetDateTime 应该在将日期写入数据库时使用,但我不明白为什么。
【问题讨论】:
-
基本上
ZonedDateTime还包含有关时区的信息,包括我阅读的夏令时切换等。
我已经阅读了文档,但我仍然不知道什么时候应该使用其中一个:
根据文档OffsetDateTime 应该在将日期写入数据库时使用,但我不明白为什么。
【问题讨论】:
ZonedDateTime 还包含有关时区的信息,包括我阅读的夏令时切换等。
问:java 8 ZonedDateTime 和 OffsetDateTime 有什么区别?
javadocs 是这样说的:
"
OffsetDateTime、ZonedDateTime和Instant都在时间线上以纳秒精度存储一个瞬间。Instant是最简单的,只是表示瞬间。OffsetDateTime添加到瞬间与 UTC/格林威治的偏移量,允许获取本地日期时间。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,那么处理 zone-id 的复杂性是......可能需要避免的事情。因此建议。
请注意,其含义/顺序随着时间的推移而不稳定的日期可能对应用程序有问题。而且由于区域规则的更改是一种极端情况,因此问题很可能在意想不到的时候出现。
建议的第二个(可能)原因是ZonedDateTime 的构造在某些点上是模棱两可的。例如,在您“拨回时钟”的时间段内,结合本地时间和 zone-id 可以为您提供两个不同的偏移量。 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 更改为@987654326 @,在大多数情况下,您的业务逻辑可能最终会出现错误。
【讨论】:
Instant 或 ZonedDateTime。 IMO OffsetDateTime 之所以存在,是因为许多现有系统(错误地)将“时间偏移”视为有关时区的足够信息(即,它们在应该传达时区名称时仅传达/存储/处理偏移量)。
ZonedDateTime & ZoneId。当我们将时间事件存储到我们转换为 UTC 的 DB 时,OffsetDateTime 基本上是一个瞬间。 UTC 日期很容易比较(避免 TZ 信息查找)。