Найдите временную метку перехода на летнее время с помощью java.util.TimeZone

Можно ли получить метку времени перехода на предыдущий и следующий летнее время с помощью Java Calendar / Date / TimeZone API?
С 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);

Есть ли способ сделать это с помощью стандартных API Java?


person Ludwig Wensauer    schedule 24.02.2009    source источник


Ответы (4)


В Java Date / Calendar / TimeZone API такой функции нет.

person tehvan    schedule 24.02.2009
comment
Есть в Java 8, см. Мой ответ - person Gov; 19.06.2017

Лучшее, что я придумал, когда мне понадобилась такая функциональность, - это использовать Календарь и перебирать весь год в указанном часовом поясе и спрашивать, является ли каждый час каждого дня началом или окончанием летнего времени.

Вы должны сделать это так, потому что на JVM Sun реализация 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;
    }
}

Конечно, имеет смысл кешировать / запоминать результат этих вычислений и т. Д.

Надеюсь это поможет.

person javashlook    schedule 24.02.2009
comment
Этот подход является рискованным, поскольку в некоторых часовых поясах летнее время было двойным, когда они переходили от стандартного к летнему, а затем от лета к двойному летнему (обычно +2 часа). В приведенном выше коде не будут обнаружены эти дополнительные переходы. - person JodaStephen; 11.11.2009

С Java 8 вы можете использовать

ZoneRules#nextTransition(Instant) 

&

ZoneRules#previousTransition(Instant) 

методы сделать то же самое.

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

person Gov    schedule 05.05.2017

Да, есть косвенный способ получить это из Java API. Проверьте это и дайте мне знать, работает ли это для проблемы:

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

Это должно дать вам необходимую информацию за текущий год, вы можете легко сделать то же самое для предыдущих лет, если хотите.

person Monis Iqbal    schedule 01.02.2010
comment
не работает с часовым поясом "Европа / Берлин". System.out.println(TimeZone.getTimeZone("Europe/Berlin")) выводит ... startMonth = 2, startDay = -1, ... endMonth = 9, endDay = -1 ... И там только дата, без времени - ›голос против. - person Ludwig Wensauer; 03.02.2010
comment
Также плохая практика - полагаться на результат метода toString () для важных вычислений. Документы Javadocs явно не определяют формат этой строки. Это означает, что он может варьироваться в зависимости от реализации виртуальной машины или измениться в будущем выпуске Java. - person Michael; 14.12.2013