Java 8 的新 Java 日期时间 API 是不是负责 DST?

Posted

技术标签:

【中文标题】Java 8 的新 Java 日期时间 API 是不是负责 DST?【英文标题】:Does Java 8's new Java Date Time API take care of DST?Java 8 的新 Java 日期时间 API 是否负责 DST? 【发布时间】:2015-12-26 08:07:57 【问题描述】:

我正在考虑使用新的 java 8 Date Time API。我用谷歌搜索了一下,发现 jodaTime 是 java 的不错选择,但仍然有兴趣了解这个新 API 是如何工作的。

我将所有时间以 UTC 值存储在我的数据存储中,并将根据用户的时区将它们转换为本地时区特定值。我可以找到许多展示如何使用新的 Java 日期时间 API 的文章。但是我不确定 API 是否会处理 DST 更改? 还是我们有更好的处理日期的方法?

我只是在学习新的 Date API ,所以想听听您对处理 DateTime 并根据用户 TimeZone 显示它的想法。

【问题讨论】:

简而言之:是的,DST 得到了照顾。 Java 8 日期时间 API 是基于 Joda 时间创建的。 @Raja 我会更正您的用语以防止混淆......日期时间工作中的“本地”意味着“任何地方”,如“圣诞节从 2015 年 12 月 25 日午夜开始”。这样的本地日期时间没有时区。确实,除非您将其调整到特定的时区,否则它没有真正的意义。 25 日的午夜在巴黎比在蒙特利尔来得更早。因此,在常见的商业应用程序中,我们很少使用“本地”。您将从数据库中获取存储的日期时间值,通常在 UTC 的业务逻辑中使用它们,并调整为 ZonedDateTime 仅用于向用户展示。 【参考方案1】:

这取决于你使用哪个类:

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

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

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

【讨论】:

感谢您提到OffsetDateTime 不支持夏令时,这正是我需要的,谢谢! localDateTime.atZone( zoneId_LosAngeles ); LocalDateTime have no concept of time-zone? @KanagaveluSugumar 因为LocalDateTime 对象不知道它嵌入的日期/时间值属于哪个时区。仅仅因为该类提供了一个 helper 方法 用于将存储的值转换为不同类型的对象,并不意味着该对象及其数据知道任何有关时区的信息。 localDateTime.atZone(zoneId) 方法是一个方便的方法,调用起来比ZonedDateTime.of(localDateTime, zoneId) 更简单,这正是它为你做的,你可以看到如果你查看源代码 的方法。【参考方案2】:

Andreas 的The Answer 是正确的。

示例代码

让我们用一些代码来测试它。 DST in the United States & Canada 今年将于 2015 年 11 月 1 日 02:00 到期。

让我们从“本地”日期时间的凌晨 1 点开始,这意味着不依赖于时间线并忽略时区问题。再加一个小时,我们就到了凌晨 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.

现在增加一个小时,看看我们得到了什么。如果忽略 DST,我们将得到凌晨 2 点。如果遵守 DST,我们将得到凌晨 1 点……当到达凌晨 2 点时,wall-clock time 会跳回到凌晨 1 点,但与 UTC 有新的偏移量。这在秋天(秋天)俗称"fall back"。

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

但在 DST 到期的当天应用时区,我们会得到不同的结果。注意一天中的时间如何保持01:00,但offset-from-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


关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

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

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

从哪里获得 java.time 类?

Java SE 8Java SE 9Java SE 10 及更高版本 内置。 标准 Java API 的一部分,带有捆绑实现。 Java 9 添加了一些小功能和修复。 Java SE 6Java SE 7 大部分 java.time 功能都在ThreeTen-Backport 中向后移植到 Java 6 和 7。 Android java.time 类的 android 捆绑包实现的更高版本。 对于早期的 Android (ThreeTenABP 项目适应 ThreeTen-Backport(如上所述)。见How to use ThreeTenABP…

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuarter 和more。

【讨论】:

感谢您的贡献...我注意到您对日期/时间 API 非常敏锐... :) 太棒了。我想我必须通过添加一个小时或使用不同的时区来手动进行夏令时转换,但 java 已经为我们做了。非常感谢【参考方案3】:

是的,Java API 将考虑 DST 更改。

本教程很好地解释了如何在时区之间转换日期以及如何选择正确的类来表示日期: 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-

【讨论】:

感谢您提醒 Orcale 文档的价值 :) 这些链接对我更有帮助。

以上是关于Java 8 的新 Java 日期时间 API 是不是负责 DST?的主要内容,如果未能解决你的问题,请参考以下文章

Java 8的日期和时间API

计算机程序的思维逻辑 (95) - Java 8的日期和时间API

Java日期时间API系列32-----Jdk8中java.time包中的新的日期时间API类应用,时间工具包 xk-time 1.0.0 版本完成。

Java日期时间API系列11-----Jdk8中java.time包中的新的日期时间API类,使用java8日期时间API重写农历LunarDate

Java日期时间API系列20-----Jdk8中java.time包中的新的日期时间API类,ZoneId时区ID大全等。

Java日期时间API系列13-----Jdk8中java.time包中的新的日期时间API类,时间类转换,Date转LocalDateTime,LocalDateTime转Date