Как вручную установить дату перехода на летнее и зимнее время в Java - PullRequest
0 голосов
/ 02 октября 2018

Моя страна изменила дату перехода на летнее время с «21 октября» на «4 ноября», и нам нужно применить это в нашем фоновом режиме.

Подходящее решение - обновить конфигурацию операционной системы., но у нас есть ограничения для этого (устаревшие зависимости).Мы ищем обходной путь.

Можно ли использовать код и программно изменить дату перехода на летнее время?

GregorianCalendar gc = new GregorianCalendar();
gc.setTimeInMillis(0);
gc.set(2018, Calendar.OCTOBER, 21, 0, 0, 0);
gc.setTimeZone(TimeZone.getTimeZone("Brazil/East"));
XMLGregorianCalendar xml = DatatypeFactory.newInstance().newXMLGregorianCalendar(gc);
System.out.println("XML Date: " + xml.toString());

Выходные данные должны быть -03:00:

XML Date: 2018-10-21T01:00:00.000-02:00

1 Ответ

0 голосов
/ 02 октября 2018

OS irrelevent

Конфигурация вашей операционной системы не имеет значения.Большинство реализаций Java по умолчанию выбирают свой начальный часовой пояс по умолчанию из хост-ОС при запуске.Но определение часовых поясов хранится в реализации Java.

средство обновления часовых поясов Java

Так что вам нужно обновить часовой поясопределения в вашей реализации Java.В большинстве реализаций используется база данных tz , также известная как tzdata .

Для реализации Java под брендом Oracle Oracle предоставляет Средство обновления часовых поясов .Эта целевая страница имеет дату 2018-08, так что, возможно, изменения вашего часового пояса были включены.Но я предлагаю вам изучить более внимательно, чтобы проверить.

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

Избегайте искажения зоны с кодом

Я настоятельно рекомендую вам избегать попыток искусственного изменения смещения самостоятельно в коде. Вы, вероятно, ошибетесь. Работа с датой и временем удивительно хитрая и запутанная.

Но если вы настаиваете, во-первых, избегайте ужасных старых устаревших классов даты и времени, таких как GregorianCalendar & Calendar & Date.Они были вытеснены несколько лет назад JSR 310. Если вам необходимо взаимодействовать со старым кодом, который еще не обновлен до java.time , выполните свою работу в современных классах, а затем в конце выполните преобразование с помощью новых методов, добавленных в старыйклассы.

Используйте современные классы java.time , в частности:

  • Instant (на мгновение в UTC)
  • OffsetDateTime (на мгновение со смещением от UTC часов-минут-секунд, но без часового пояса)
  • ZonedDateTime (на мгновение в определенном часовом поясе)

С помощью этих классов вы можете выполнить поиск переполнения стека для многих существующих примеров и объяснений.Вы должны сосредоточиться на OffsetDateTime, ZoneOffset (вместо ZoneId) и Instant, так как вы должныизбегайте ZonedDateTime, если вы знаете, что ваш файл tzdata устарел.

тот же момент, другое время на настенных часах

enter image description here

OffsetDateTime::withOffsetSameInstant​

OffsetDateTime odt = OffsetDateTime.parse( "2018-10-21T01:00:00.000-02:00" ) ;
ZoneOffset offset = ZoneOffset.ofHours( -3 ) ;
OffsetDateTime odt2 = odt.withOffsetSameInstant​( offset ) ;  // Same moment, same point on the timeline, different wall-clock time.

odt.toString (): 2018-10-21T01: 00-02: 00

odt2.toString (): 2018-10-21T00: 00-03: 00

В этом примере odt и odt2 представляют один и тот же одновременный момент, одну и ту же точку на временной шкале.Если вы извлечете Instant (значение в формате UTC), ваши результаты будут в тот же момент.Только время их настенных часов отличается.

Instant instant1 = odt.toInstant() ;  // Adjust to UTC.
Instant instant2 = odt2.toInstant() ;
boolean sameMoment = instant1.equals( instant2 ) ; 

instant1.toString (): 2018-10-21T03: 00: 00Z

instant2.toString (): 2018-10-21T03: 00: 00Z

sameMoment = true

Z в конце означает UTC, нулевое смещение от UTC, +00:00.Z произносится как "зулу".Определяется стандартом ISO 8601 .

Другой момент, то же время на настенных часах

enter image description here

OffsetDateTime::withOffsetSameLocal​

Напротив, вы можете задать время суток, таким образом представляя другой момент.Для этого используйте метод withOffsetSameLocal.Помните, что вы меняете значение данных , вы перемещаетесь в другую точку на временной шкале.

OffsetDateTime differentMomentButSameTimeOfDay = odt. withOffsetSameLocal( offset ) ;

differentMomentButSameTimeOfDay.toString (): 2018-10-21T01: 00-03: 00

Извлеките момент, чтобы увидеть, что у нас другой момент.

Instant differentInstant = differentMomentButSameTimeOfDay.toInstant() ;

differentInstant.toString (): 2018-10-21T04: 00: 00Z

Обратите внимание на 4:00 UTC против 3:00 UTC, как показано выше.Этот момент здесь происходит через час после момента выше.Две разные точки на временной шкале.

Не пытайтесь выполнять эту работу до тех пор, пока вы полностью не поймете концепцию точек на временной шкале, и переход между точками будет полностью отличаться от настройки смещений.Практикуйтесь, прежде чем делать реальную работу.Нерешительные догадки приведут вас в мир боли и головной боли.

И, как я уже говорил выше, ваше время было бы гораздо лучше потратить на установку обновленных tzdata файлов, чем на взлом этих смещений.

Live code

См. Весь приведенный выше код Запустите live на IdeOne.com .

Обновите tzdata везде

Для достижения наилучших результатов вам следует обновить tzdata (или эквивалент) во всех этих различных местах:

  • Ваши операционные системы
  • Ваши JVM
  • Ваши механизмы баз данных, такие как Postgres
  • Любые библиотеки, объединяющие собственную информацию о часовом поясе (например: Joda-Time )

О java.time

Фреймворк java.time встроен в Java 8 и более поздние версии.Эти классы вытесняют старые классные устаревшие классы даты и времени, такие как java.util.Date, Calendar и & SimpleDateFormat.

Проект Joda-Time , теперь в режиме обслуживания , рекомендует перейти на классы java.time .

Чтобы узнать больше, см. Oracle Tutorial .И поиск переполнения стека для многих примеров и объяснений.Спецификация: JSR 310 .

Вы можете обмениваться java.time объектами непосредственно с вашей базой данных.Используйте драйвер JDBC , совместимый с JDBC 4.2 или более поздней версии.Нет необходимости в строках, нет необходимости в java.sql.* классах.

Где получить классы java.time?

  • Java SE 8 , Java SE 9 , Java SE 10, Java SE 11 и более поздние версии - часть стандартного Java API с связанной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и JavaSE 7
    • Большая часть функций java.time перенесена на Java 6 & 7 в ThreeTen-Backport .
  • Android
    • Более поздние версии пакетов Android для реализации java.time классы.
    • Для более ранних версий Android (<26) проект <a href="https://github.com/JakeWharton/ThreeTenABP" rel="nofollow noreferrer"> ThreeTenABP адаптируется ThreeTen-Backport (упомянуто выше).См. Как использовать ThreeTenABP… .

ThreeTen-Extra Проект расширяет java.time дополнительными классами.Этот проект является полигоном для возможных будущих дополнений к java.time.Здесь вы можете найти несколько полезных классов, таких как Interval, YearWeek, YearQuarter и more .

...