Java 8的新Java日期时间API是否考虑了夏令时?

30

我在考虑使用新的Java 8 Date Time API。我进行了一些搜索,发现jodaTime是Java的一个不错选择,但仍然很想看看这个新API的工作方式。

我将所有时间都存储为UTC值,并将根据用户的时区将它们转换为本地时区特定的值。我可以找到许多文章显示如何使用新的Java Date Time API。然而,我不确定API是否会处理DST更改?或者我们有没有更好的处理日期的方法?

我正在学习新的Date API,所以想听听您关于如何处理日期时间并根据用户时区显示它的想法。


3
简而言之:是的,DST已得到处理。 Java 8日期时间API是基于Joda时间创建的。 - Mick Mnemonic
2
@Raja我会更正你的术语以防止混淆... 在日期时间工作中,“本地”意味着“适用于任何地方”,例如“圣诞节从2015年12月25日午夜开始”。这样的本地日期时间没有时区。事实上,除非您将其调整到特定的时区,否则它没有实际意义。在巴黎,25日午夜比蒙特利尔早。因此,在常见的业务应用程序中,我们很少使用“本地”。您将从数据库中获取存储的日期时间值,在业务逻辑中通常使用UTC进行处理,并仅在向用户呈现时调整为ZonedDateTime。 - Basil Bourque
3个回答

47

这取决于你使用的类:

  • Instant 是全球时间线(UTC)上的即时时间点,与时区无关。
  • LocalDateLocalDateTime 没有时区的概念,但调用 now() 当然会给出正确的时间。
  • OffsetDateTime 有一个时区,但不支持夏令时。
  • ZonedDateTime 具有完整的时区支持。

它们之间的转换通常需要一个时区,因此回答你的问题:

    是的,Java 8日期/时间可以处理夏令时,如果你使用得当。


感谢提到OffsetDateTime不支持夏令时,这正是我所需要的,谢谢! - Clint Eastwood
localDateTime.atZone(zoneId_LosAngeles); <--- 所以LocalDateTime接受时区,那么为什么这个答案说LocalDateTime没有时区的概念 - Kanagavelu Sugumar
2
@KanagaveluSugumar 因为 LocalDateTime 对象没有概念,不知道嵌入的日期/时间值属于哪个时区。仅仅因为该类提供了一个将存储的值转换为其他类型对象的 辅助方法,并不意味着该对象及其数据知道任何关于时区的信息。localDateTime.atZone(zoneId) 方法是一个 便利方法,使得调用比 ZonedDateTime.of(localDateTime, zoneId) 更简单,这正是它为您完成的工作,如果您 查看该方法的源代码,就会发现这一点。 - Andreas

43

答案Andreas提供,完全正确。

示例代码

让我们使用一些代码进行测试。美国和加拿大的DST将于2015年11月1日02:00到期。

让我们从“本地”日期时间开始,即不与时间线相关并忽略时区问题。再加一个小时,我们就得到了2点钟。很有道理。

LocalDateTime localDateTime = LocalDateTime.of( 2015 , Month.NOVEMBER , 1 , 1 , 0 ); // 1 AM anywhere. Not tied the timeline nor to any time zone.
LocalDateTime localDateTimeOneHourLater = localDateTime.plusHours( 1 ); // 2 AM anywhere, in no particular time zone, ignoring DST.

下面我们来具体说明,针对特定的时区。我们将任意一个1点钟的时间放入美国西海岸的时区America/Los_Angeles中。
ZoneId zoneId_LosAngeles = ZoneId.of( "America/Los_Angeles" );
ZonedDateTime before = localDateTime.atZone( zoneId_LosAngeles ); // Assign a time zone, tying this vague date-time idea/generality to an actual moment on the time line.

现在加一小时,看看我们得到什么。如果忽略夏令时,我们会得到凌晨2点。如果尊重夏令时,我们会得到凌晨1点...当时间到达凌晨2点时,挂钟时间会跳回到凌晨1点,但具有新的偏移量。这在秋季俗称为"回拨"
ZonedDateTime after = before.plusHours( 1 ); // 2 AM? Nope, 1 AM because DST Daylight Saving Time expires at 2 AM Nov 1, 2015.

将数据输出到控制台。

System.out.println( "localDateTime : " + localDateTime );
System.out.println( "localDateTimeOneHourLater : " + localDateTimeOneHourLater );
System.out.println( "before : " + before );
System.out.println( "after : " + after );

当运行时,我们会得到这个输出。没有时区的情况下,1点加1小时等于2点。请记住这些是“本地”日期时间值,而不是UTC。它们仅代表日期时间的模糊概念,而不是时间轴上的实际时刻。
localDateTime : 2015-11-01T01:00
localDateTimeOneHourLater : 2015-11-01T02:00

但是,当夏令时结束那天应用时区后,我们会得到不同的结果。请注意,时间保持为01:00,但与UTC的偏移量-07:00变为-08:00

before : 2015-11-01T01:00-07:00[America/Los_Angeles]
after : 2015-11-01T01:00-08:00[America/Los_Angeles]

也许如果我们将其调整为UTC时间,这样会更清晰易于验证。我们可以通过将beforeafter对象作为Instant对象访问来实现。然后System.out.println隐式地调用toString方法。
System.out.println( "before.toInstant : " + before.toInstant() );
System.out.println( "after.toInstant : " + after.toInstant() );

运行时。

before.toInstant : 2015-11-01T08:00:00Z
after.toInstant : 2015-11-01T09:00:00Z

Table of date-time types in Java, both modern and legacy


关于 java.time

java.time 框架是内置于 Java 8 及更高版本中的。这些类替代了老旧的 遗留 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

Joda-Time项目现在处于维护模式,建议迁移到java.time类。

欲了解更多信息,请参阅Oracle教程。并在Stack Overflow上搜索许多示例和解释。规范为JSR 310

您可以直接与数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC驱动程序。无需字符串,也不需要java.sql.*类。

如何获取java.time类?

ThreeTen-Extra 项目通过增加额外的类来扩展 java.time。该项目是 java.time 可能未来添加的试验场。您可能会在这里找到一些有用的类,例如Interval, YearWeek, YearQuarter,以及更多


感谢您的贡献... 我注意到您对日期/时间API有相当深厚的理解力... :) - Edward J Beckett
太好了。我原本以为我需要手动添加一小时或使用不同的时区来进行夏令时转换,但 Java 已经为我们自动完成了。非常感谢。 - iAmLearning

5
是的,Java API会考虑到夏令时的变化。
本教程很好地解释了如何在不同时区之间转换日期以及如何选择正确的日期类来表示日期: https://docs.oracle.com/javase/tutorial/datetime/iso/timezones.html 您还可以查看此类,该类表示每个区域的规则: http://docs.oracle.com/javase/8/docs/api/java/time/zone/ZoneRules.html 特别地,此方法可以告诉您特定时刻是否处于夏令时: http://docs.oracle.com/javase/8/docs/api/java/time/zone/ZoneRules.html#isDaylightSavings-java.time.Instant-

谢谢您提醒我 Oracle 文档的价值 :) 这些链接对我非常有帮助。 - Raja

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接