Рубрики
Без рубрики

Обработка летнего времени экономии времени на Java

Узнайте, как учесть DST на Java.

Автор оригинала: Andrea Ligios.

Обработка летнего времени экономии времени на Java

1. Обзор

Летнее время , или DST, это практика продвижения часов в летние месяцы для того, чтобы использовать дополнительный час естественного света (экономия тепла, освещение власти, повышение настроения, и так далее).

Он используется несколько стран и должны быть приняты во внимание при работе с датами и временем.

В этом учебнике мы увидим, как правильно обрабатывать DST в Java в зависимости от различных мест.

2. JRE и DST Mutability

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

Страна, а в некоторых случаях даже город, может решить, если и как применить или отменить его.

Каждый раз, когда это происходит, изменение записывается в База данных часовых поясов IANA , и обновление будет развернуто в будущем выпуск JRE .

В случае, если это невозможно подождать, мы можем заставить измененные данные Часового пояса, содержащие новые настройки DST в jrE через официальный инструмент Oracle под названием Инструмент обновления часовой зоны Java , доступны на Java SE скачать страницу .

3. Неправильный путь: Трехтысяй идентификатор часового пояса

Еще в JDK 1,1 дней, API позволило трех букв часового пояса IDs, но это привело к ряду проблем.

Во-первых, это произошло потому, что один и тот же трехпомохий идентификатор может относиться к нескольким часовым поясам. Например, CST может быть США “Центральное стандартное время”, но и “Китайское стандартное время”. Платформа Java могла распознать только одну из них.

Другая проблема заключается в том, что стандартные часовые пояса никогда не принимают летнее время в учетную запись. Несколько областей/регионов/городов могут иметь свой локальный DST в одном и том же стандартном часовом поясе, поэтому Стандартное время не соблюдает его.

Из-за обратной совместимости это еще можно мгновенно java.util.Timezone с трех букв. Тем не менее, этот метод является deprecated и не должны использоваться больше.

4. Правильный путь: идентификатор часового пояса ТДБ

Правильный способ обработки DST в Java заключается в мгновенном Тайм- с конкретным идентификатором часового пояса ТДБ, например. “Европа/Рим”.

Затем мы будем использовать это в сочетании с конкретными временем классами, такими как java.util.Calendar чтобы получить правильную конфигурацию Время в необработанную компенсацию (в часовой пояс GMT) и автоматические корректировки смены DST.

Давайте посмотрим, как переход от GMT-1 GMT-2 (что происходит в Италии 25 марта 2018 года в 02:00) автоматически обрабатывается при использовании правильного Таймзон:

TimeZone tz = TimeZone.getTimeZone("Europe/Rome");
TimeZone.setDefault(tz);
Calendar cal = Calendar.getInstance(tz, Locale.ITALIAN);
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.ITALIAN);
Date dateBeforeDST = df.parse("2018-03-25 01:55");
cal.setTime(dateBeforeDST);
 
assertThat(cal.get(Calendar.ZONE_OFFSET)).isEqualTo(3600000);
assertThat(cal.get(Calendar.DST_OFFSET)).isEqualTo(0);

Как мы видим, ZONE_OFFSET 60 минут (потому что Италия GMT-1 ) в то время как DST_OFFSET 0 в то время.

Давайте добавим десять минут к Календарь :

cal.add(Calendar.MINUTE, 10);

Теперь DST_OFFSET стало 60 минут тоже, и страна перешла свое местное время от CET (Центральноевропейские времена) CEST (Центральноевропейские летние времена), которое GMT-2 :

Date dateAfterDST = cal.getTime();
 
assertThat(cal.get(Calendar.DST_OFFSET))
  .isEqualTo(3600000);
assertThat(dateAfterDST)
  .isEqualTo(df.parse("2018-03-25 03:05"));

Если мы отобразить две даты в консоли, мы увидим изменение часового пояса, а также:

Before DST (00:55 UTC - 01:55 GMT+1) = Sun Mar 25 01:55:00 CET 2018
After DST (01:05 UTC - 03:05 GMT+2) = Sun Mar 25 03:05:00 CEST 2018

В качестве заключительного теста мы можем измерить расстояние между двумя Дата s, 1:55 и 3:05:

Long deltaBetweenDatesInMillis = dateAfterDST.getTime() - dateBeforeDST.getTime();
Long tenMinutesInMillis = (1000L * 60 * 10);
 
assertThat(deltaBetweenDatesInMillis)
  .isEqualTo(tenMinutesInMillis);

Как и следовало ожидать, расстояние составляет 10 минут вместо 70.

Мы видели, как избежать попадания в общие ловушки, с которыми мы можем столкнуться при работе с Дата путем правильного использования Таймзон и Локале .

5. Лучший способ: Java 8 Дата/время API

Работа с этими потоками небезопасных и не всегда удобный java.util классы всегда были жесткими, особенно из-за проблем совместимости, которые не позволяли им должным образом рефакторинг.

По этой причине Java 8 представила совершенно новый пакет, который java.time , и совершенно новый набор API, Api даты/времени. Это ISO-ориентированный, полностью поток-безопасный и сильно вдохновлен знаменитой библиотекой Joda-Time.

Давайте более подробно рассмотрим новые классы, начиная с преемника java.util.Date , java.time.LocalDateTime :

LocalDateTime localDateTimeBeforeDST = LocalDateTime
  .of(2018, 3, 25, 1, 55);
 
assertThat(localDateTimeBeforeDST.toString())
  .isEqualTo("2018-03-25T01:55");

Мы можем наблюдать, как Местное время соответствует ISO8601 профиль, стандартная и широко принятая дата-время нотации.

Он совершенно не знает об Зоны и Смещение , однако, именно поэтому мы должны преобразовать его в полностью до н.д.-знать java.time.ZonedDateTime :

ZoneId italianZoneId = ZoneId.of("Europe/Rome");
ZonedDateTime zonedDateTimeBeforeDST = localDateTimeBeforeDST
  .atZone(italianZoneId);
 
assertThat(zonedDateTimeBeforeDST.toString())
  .isEqualTo("2018-03-25T01:55+01:00[Europe/Rome]"); 

Как мы видим, в настоящее время дата включает в себя два основных задней части информации: 01:00 является ЗонаОффсет , в то время как (Европа/Рим) является ЗонаИд .

Как и в предыдущем примере, давайте запускаем DST через добавление десяти минут:

ZonedDateTime zonedDateTimeAfterDST = zonedDateTimeBeforeDST
  .plus(10, ChronoUnit.MINUTES);
 
assertThat(zonedDateTimeAfterDST.toString())
  .isEqualTo("2018-03-25T03:05+02:00[Europe/Rome]");

Опять же, мы видим, как и время, и зона смещения смещаются вперед, и по-прежнему сохраняя то же расстояние:

Long deltaBetweenDatesInMinutes = ChronoUnit.MINUTES
  .between(zonedDateTimeBeforeDST,zonedDateTimeAfterDST);
assertThat(deltaBetweenDatesInMinutes)
  .isEqualTo(10);

6. Заключение

Мы видели, что такое летнее время и как справиться с ним с помощью некоторых практических примеров в различных версиях Java core API.

При работе с Java 8 и выше, использование новых java.time пакет поощряется благодаря простоте использования и его стандартной, без резьбовой природы.

Как всегда, полный исходный код доступен более на Github .