Java如何确定指定日期是否处于夏令时(DST)状态

77

我有一个Java类,它输入一个位置的纬度/经度,并在夏令时开启和关闭时返回GMT偏移量。我想找到一种简单的方法,在Java中确定当前日期是否在夏令时,以便我可以应用正确的偏移量。目前,我只在美国的时区执行这个计算,尽管最终我也想将其扩展到全球各个时区。


目前我正在使用GeoTools库和美国国家地图局提供的一个形状文件来检索时区信息(http://nationalatlas.gov/mld/timeznp.html)。幸运的是,这为我提供了一些额外的信息 - 主要是时区符号,它是2或4个数字(即AL,EA,EAno等)。不幸的是,这个值与Java时区使用的值不对应,尽管我可以手动执行此映射。理想情况下,如果我用世界时区形状文件替换此文件,我希望有一个解决方案,但这可能太雄心壮志了。 - gelgamil
timeznp020.txt 列出了包含每个缩写的详细信息的“枚举域”,将它们映射到zoneinfo时区名称应该不太困难。我不确定Java中的时区名称是否跨平台,但我希望如此! - tc.
另一个对于这个问题有用的答案:https://dev59.com/YXM_5IYBdhLWcg3wRw51#1449510 - Scott
https://dev59.com/Emkv5IYBdhLWcg3wghEh - user4761989
5个回答

87

这是针对提问机器的答案:

TimeZone.getDefault().inDaylightTime( new Date() );

服务器需要确定客户端的时区才能解决这个问题。有关原因,请参见@Powerlord的答案。

对于任何特定的时区

TimeZone.getTimeZone( "US/Alaska").inDaylightTime( new Date() );

1
我一直在处理这个问题。我还没有找到世界时区的形状文件。 - Clint
我们不知道这是桌面应用程序还是Web应用程序。然而,Web应用程序无法访问客户端的时区信息。 - Powerlord
Android:需要API级别24。 - Bryan Bryce
自Java 8以来,最好使用ZoneId而不是TimeZone,请查看Basil Bourque的答案,这是正确的Java 8后答案。 - Chris

64

简而言之

ZoneId.of( "America/Montreal" )  // Represent a specific time zone, the history of past, present, and future changes to the offset-from-UTC used by the people of a certain region.  
      .getRules()                // Obtain the list of those changes in offset. 
      .isDaylightSavings(        // See if the people of this region are observing Daylight Saving Time at a specific moment.
          Instant.now()          // Specify the moment. Here we capture the current moment at runtime. 
      )                          // Returns a boolean.

java.time

这里是现代版的java.time(请参见Tutorial),由mamboking提供正确答案。请注意,不要修改HTML标签。 示例代码:
ZonedDateTime now = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) );
…
ZoneId z = now.getZone();
ZoneRules zoneRules = z.getRules();
Boolean isDst = zoneRules.isDaylightSavings( now.toInstant() );

请注意,上述代码中的最后一行我们需要通过简单调用 toInstantZonedDateTime 对象中提取一个 Instant 对象。

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更多


10
TimeZone tz = TimeZone.getTimeZone("EST");
boolean inDs = tz.inDaylightTime(new Date());

8
应避免使用三个类似于 EST(表示标准时间)的缩写词,因为它们对夏时制不敏感。应使用时区标识符。 - Tiny
@Tiny,情况比这更令人困惑:其中一些是DST敏感的,而另一些则不是。有充分的理由避免使用它们。(在2021年,我们也应该避免使用老式的TimeZone类,而改用ZoneId)。 - Ole V.V.

3
你需要更进一步地使用这些坐标,找出它们所在的时区。一旦你知道了是哪个时区,isDayLight() 方法会很有用。
例如,你无法确定 -0500 是 EST(美国/加拿大东部标准时间),CDT(美国/加拿大中部夏令时),COT(哥伦比亚时间),AST(巴西阿克里州标准时间),ECT(厄瓜多尔时间)等等。
其中一些可能支持夏令时,也可能不支持。

1

我之前研究过GeoNames网络服务,我知道它可以实现我想要做的事情。不幸的是,这段代码将托管在可能位于防火墙后面的服务器上,因此如果可能的话,我会尽量避免外部网络服务调用。对于那些没有此限制的人来说,GeoNames网络服务将是一个很好的解决方案。 - gelgamil

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