【问题标题】:Find DST transition timestamp with java.util.TimeZone使用 java.util.TimeZone 查找 DST 转换时间戳
【发布时间】:2010-10-09 13:21:11
【问题描述】:

是否可以使用 Java 日历/日期/时区 API 获取上一个和下一个 DST 转换时间戳?
使用Joda-Time 我可以写:

DateMidnight today = new DateMidnight(2009, 2, 24);
DateTimeZone zone = today.getZone();

DateTime previousTransition =
    new DateTime(zone.previousTransition(today.getMillis()));
// 2008-10-26T02:59:59.999+02:00 for Europe/Berlin
System.out.println(previousTransition);

DateTime nextTransition =
    new DateTime(zone.nextTransition(today.getMillis()));
// 2009-03-29T03:00:00.000+02:00 for Europe/Berlin
System.out.println(nextTransition);

有没有办法使用标准的 Java API 来做到这一点?

【问题讨论】:

    标签: java jodatime


    【解决方案1】:

    java Date/Calendar/TimeZone API 中没有这样的功能

    【讨论】:

    • Java 8中有,看我的回答
    【解决方案2】:

    当我需要这样的功能时,我想出的最好方法是使用日历并在指定时区遍历整年,并询问每天的每个小时是 DST 的开始还是结束。

    您必须这样做,因为在 Sun 的 JVM 上,TimeZone (sun.util.calendar.ZoneInfo) 的实现以某种“编译”形式保存有关时区转换的数据。

    代码如下:

    public class Dst {
        Date start;
        Date end;
    
        public static Dst calculate(TimeZone tz, int year) {
            final Calendar c = Calendar.getInstance(tz);
            c.setLenient(false);
            c.set(year, Calendar.JANUARY, 1, 1, 0, 0);
            c.set(Calendar.MILLISECOND, 0);
    
            if (tz.getDSTSavings() == 0) {
                return null;
            }
    
            Dst dst = new Dst();
    
            boolean flag = false;
    
            do {
                Date date = c.getTime();
                boolean daylight = tz.inDaylightTime(date);
    
                if (daylight && !flag) {
                    flag = true;
                    dst.start = date;
                }
                else if (!daylight && flag) {
                    flag = false;
                    dst.end = date;
                }
    
                c.add(Calendar.HOUR_OF_DAY, 1);
            }
            while (c.get(Calendar.YEAR) == year);
    
            return dst;
        }
    }
    

    当然,缓存/记忆这些计算的结果等是有意义的。

    希望这会有所帮助。

    【讨论】:

    • 这种方法是有风险的,因为一些时区有双夏令时,从标准时间到夏季,然后从夏季到双夏季(通常 +2 小时)。上面的代码不会捕捉到那些额外的转换。
    【解决方案3】:

    在 Java 8 中,您可以使用

    ZoneRules#nextTransition(Instant) 
    

    &

    ZoneRules#previousTransition(Instant) 
    

    做同样事情的方法。

    https://docs.oracle.com/javase/8/docs/api/java/time/zone/ZoneRules.html

    【讨论】:

      【解决方案4】:

      是的,有一种间接的方法可以从 Java API 中检索它。看看这个,让我知道这是否能解决问题:

      http://monisiqbal.blogspot.com/2009/12/retrieving-time-zones-dst-information.html

      这应该为您提供当年所需的信息,如果您愿意,您可以轻松地为往年做同样的事情。

      【讨论】:

      • 不适用于“欧洲/柏林”时区。 System.out.println(TimeZone.getTimeZone("Europe/Berlin")) 打印 ...startMonth=2,startDay=-1,...endMonth=9,endDay=-1..." 而且只有日期,没有时间 -> 否决票。
      • 依赖 toString() 方法的结果进行重要计算也是不好的做法。 Javadocs 没有明确定义此字符串的格式。这意味着它可能会因 VM 实现或未来 Java 版本的变化而有所不同。
      猜你喜欢
      • 2015-04-20
      • 1970-01-01
      • 1970-01-01
      • 2013-03-06
      • 2014-03-17
      • 1970-01-01
      • 2016-10-23
      • 2013-04-15
      • 2017-09-02
      相关资源
      最近更新 更多