java 8 ZonedDateTime和OffsetDateTime有什么区别?

Zhe*_*nya 143 java java-8 java-time

我已经阅读了文档,但是当我应该使用其中一个时,我仍然无法获得:

根据文档OffsetDateTime应该在将日期写入数据库时​​使用,但我不明白为什么.

Ste*_*n C 172

javadocs说:

" OffsetDateTime,ZonedDateTime并且Instant所有都在时间线上存储到纳秒精度.Instant最简单,只是代表瞬间.OffsetDateTime增加了从UTC /格林威治的偏移瞬间,这允许获得本地日期时间.ZonedDateTime增加全时区域规则."

资料来源:https://docs.oracle.com/javase/8/docs/api/java/time/OffsetDateTime.html

因此,OffsetDateTime和之间的区别在于ZonedDateTime后者包括涵盖夏令时调整的规则.

在将日期写入数据库时​​应该使用OffsetDateTime,但我不明白为什么.

一个原因是具有局部时间偏移的日期总是代表相同的时刻,因此具有稳定的排序.相比之下,面对对各个时区的规则进行调整,具有全时区信息的日期的含义是不稳定的.(这些确实发生了......)

如果(例如)在日期的字段上创建数据库索引,则其含义/排序不稳定的日期会出现问题.


GMs*_*soF 31

接受的答案给出了非常完整的解释,也许下面的代码示例可以为您提供简短而清晰的图片:

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
Run Code Online (Sandbox Code Playgroud)

简而言之,ZonedDateTime仅当您想要考虑夏令时时才使用,通常会有一小时的差异,如上面的示例所示,ZonedDateTime-5:00到的偏移量变化-04:00,在大多数情况下,您的业务逻辑可能最终会出现错误。

(代码复制自https://www.youtube.com/watch?v=nEQhx9hGutQ

  • 我会采取相反的方式:正确使用的通常是*“Instant”或“ZonedDateTime”。IMO `OffsetDateTime` 的存在只是因为许多现有系统(错误地)将“时间偏移”视为有关时区的充分信息(即,当它们应该传达时区名称时,它们仅传达/存储/处理偏移量)。 (11认同)
  • @JoachimSauer 当我们为用户格式化消息或读取他们的输入时,我们使用“ZonedDateTime”和“ZoneId”。当我们将时间事件存储到数据库时,我们将其转换为 UTC,OffsetDateTime 基本上是一个即时时间。UTC 日期很容易比较(避免 TZ 信息查找)。 (4认同)