在Java中获取时区夏令时转换日期

20

我想知道在Java中获取未来夏令时变更日期列表的最简单方法。

一种比较笨拙的方法是遍历几年的天数,对TimeZone.inDaylightTime()进行测试。虽然这样做能够实现目标,而且由于每次应用启动时都需要运行此代码,所以效率并不是我的主要担忧,但我想知道是否有更简单的方法。

如果您想知道我为什么要这样做,那是因为我有一个JavaScript应用程序,需要处理包含UTC时间戳的第三方数据。我想要可靠地在客户端从GMT转换为EST。请参见Javascript -- Unix Time to Specific Time Zone。我已编写了一些JavaScript代码来完成此操作,但我希望从服务器获取准确的转换日期。


2
请查看此问题:https://dev59.com/ckbRa4cB1Zd3GeqP2qsC - Rich Seller
2个回答

34

Joda Time(与往常一样)由于其 DateTimeZone.nextTransition 方法使这个过程非常容易。例如:

import org.joda.time.*;
import org.joda.time.format.*;

public class Test
{    
    public static void main(String[] args)
    {
        DateTimeZone zone = DateTimeZone.forID("Europe/London");        
        DateTimeFormatter format = DateTimeFormat.mediumDateTime();

        long current = System.currentTimeMillis();
        for (int i=0; i < 100; i++)
        {
            long next = zone.nextTransition(current);
            if (current == next)
            {
                break;
            }
            System.out.println (format.print(next) + " Into DST? " 
                                + !zone.isStandardOffset(next));
            current = next;
        }
    }
}

输出:

2009年10月25日01:00:00 进入夏令时?false
2010年3月28日02:00:00 进入夏令时?true
2010年10月31日01:00:00 进入夏令时?false
2011年3月27日02:00:00 进入夏令时?true
2011年10月30日01:00:00 进入夏令时?false
2012年3月25日02:00:00 进入夏令时?true
2012年10月28日01:00:00 进入夏令时?false
2013年3月31日02:00:00 进入夏令时?true
2013年10月27日01:00:00 进入夏令时?false
2014年3月30日02:00:00 进入夏令时?true
2014年10月26日01:00:00 进入夏令时?false
2015年3月29日02:00:00 进入夏令时?true
2015年10月25日01:00:00 进入夏令时?false
...

使用Java 8,可以使用其nextTransitionpreviousTransition方法,通过ZoneRules获取相同的信息。


对于“样例即将到来”的想法(当然,还包括其他回答),我给出了一个赞同。 - akf
7
@Silence:现在是3月28日,位于代码指定的伦敦时区。并非所有人都在美国... - Jon Skeet
+1 但是,谁使用这个解决方案必须记住,joda-time将zoninfo文件编译到其jar中,并不使用JDK的文件,如此处所述http://joda-time.sourceforge.net/tz_update.html。 - A.B.Cade
我希望有一种方法可以在没有任何第三方API的情况下实现这个。 - bluelurker
3
在Java 8中,你可以使用ZoneRules.nextTransitionZoneRules.previousTransition。我已经在我的回答中编辑了一个链接。 - Jon Skeet
显示剩余3条评论

7

java.time

现代的解决方案使用java.time,这是现代Java日期和时间API。
    ZoneId zone = ZoneId.of("Europe/London");
    ZoneRules rules = zone.getRules();
    ZonedDateTime now = ZonedDateTime.now(zone);
    ZoneOffsetTransition transition = rules.nextTransition(now.toInstant());
    Instant max = now.plusYears(15).toInstant();
    while (transition != null && transition.getInstant().isBefore(max)) {
        System.out.println(transition);
        transition = rules.nextTransition(transition.getInstant());
    }

输出,简称:

Transition[Overlap at 2019-10-27T02:00+01:00 to Z]
Transition[Gap at 2020-03-29T01:00Z to +01:00]
Transition[Overlap at 2020-10-25T02:00+01:00 to Z]
Transition[Gap at 2021-03-28T01:00Z to +01:00]
Transition[Overlap at 2021-10-31T02:00+01:00 to Z]
Transition[Gap at 2022-03-27T01:00Z to +01:00]
Transition[Overlap at 2022-10-30T02:00+01:00 to Z]
(cut)
Transition[Overlap at 2033-10-30T02:00+01:00 to Z]
Transition[Gap at 2034-03-26T01:00Z to +01:00]
我不会过分信任数据。我不确定英国脱欧后(以及欧盟在2021年放弃夏令时后)时间会发生什么。

链接: Oracle教程:日期时间,解释如何使用java.time。


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