Установка смещения часового пояса в времени java 8 против времени joda - PullRequest
0 голосов
/ 30 октября 2019

Я работаю в организации в двух местах. Одним из них является Чили, где летнее время крайне непредсказуемо и часто меняется из года в год. У нас есть приложение, которое зависит от времени и до сих пор, использовали время йода. Когда чилийское правительство решает изменить летнее время, мы используем код joda, чтобы установить смещение по умолчанию DateTimeZone:

/**
 * Updates the default time zone, i.e. the time zone which is used as local time.
 */
 private void updateDefaultTimeZone() {
    if (isEmpty(Configuration.Value.TIME_ZONE_OFFSET)) {
        // make the site's default time zone the current time zone for joda time,
        // this should always be the case for the non-Chile site, and work for the Chile site during most of the year
        DateTimeZone.setDefault(siteService.getSiteTimeZone());
    } else {
        // makes a user defined time zone the current time zone for joda time
        // this will be used when Chile is delaying or pulling forward the transition from/to daylight
        // saving time and the JVM is therefore not able to calculate the local times appropriately
        Integer offset = getInteger(Configuration.Value.TIME_ZONE_OFFSET);
        DateTimeZone.setDefault(DateTimeZone.forOffsetHours(offset));
    }
}

Мы пытаемся перевести нашу кодовую базу с времени joda на время Java 8, но я действительно понятия не имею, какие классы участвуют в создании чего-то подобного. Я предполагаю, возможно ZoneRules, но я не уверен. Есть ли у кого-нибудь какие-либо советы о том, как наиболее просто выполнить это?

Кроме того, каков наилучший способ преобразования единиц в Java 8 раз? Скажем, у меня есть 24 часа, и я хочу перевести это в дни. (Я спрашиваю, потому что в этом случае кажется, что многие методы работают с миллисекундами, и я хочу работать с часами, но думаю, что должен быть лучший встроенный способ преобразования, чем делать арифметику вручную.)

Ответы [ 2 ]

3 голосов
/ 31 октября 2019

Использование java.util.TimeZone.setDefault(TimeZone). Поскольку JSR-310 java.time.* интегрирован с JDK, нет необходимости в отдельном методе.

(Для преобразования единиц может оказаться, что проще всего использовать TimeUnit, но, возможно, отдельный более сфокусированныйвопрос поможет тебе там.)

1 голос
/ 31 октября 2019

JodaStephen сказал это . Он является ведущим разработчиком Joda-Time и java.time, так что, безусловно, авторитет здесь. Я добавлю лишь несколько дополнительных соображений.

Не стоит полагаться на часовой пояс по умолчанию

Часовой пояс JVM по умолчанию можно изменить в любой момент из другой части вашей программы и из других программ. работает в той же JVM. Так что полагаться на это хрупко. java.time (время Java 8) постоянно предлагает вам возможность указывать часовой пояс для всех операций, чувствительных к часовому поясу. Моя привычка использовать это. Поэтому я предлагаю вам сохранить часовой пояс где-нибудь в вашей программе, где вы один контролируете, кто вмешивается в него, и кодируете свои операции даты и времени, чтобы использовать этот сохраненный параметр, а не часовой пояс по умолчанию для JVM.

Если , вы по-прежнему полагаетесь на значение по умолчанию: класс TimeZone имеет плохой недостаток дизайна. С первого взгляда это будет звучать так:

    TimeZone.setDefault(TimeZone.getTimeZone("America/Santiago_de_Chile"));

Это не так! Посмотрите на вывод из

    System.out.println(TimeZone.getDefault().getID());

GMT

Чрезвычайно запутанное ИМХО. Правильный идентификатор часового пояса: Америка / Сантьяго, а не Америка / Сантьяго_д_Чили. Таким образом, мы должны были ожидать IllegalArgumentException или подобное здесь. Вместо этого TimeZone просто молчаливо дает нам совершенно неправильный часовой пояс GMT.

Вместо этого используйте:

    TimeZone.setDefault(TimeZone.getTimeZone(ZoneId.of("America/Santiago_de_Chile")));

Исключение в потоке "main" java.time.zone.ZoneRulesException: Неизвестный идентификатор часового пояса: America / Santiago_de_Chile

Преобразование единиц времени

Как и JodaStephen, я обычно использую TimeUnit для преобразований единиц времени, но я пытаюсь вспомнить, прежде чем дважды подуматьпри этом.

    System.out.println(TimeUnit.HOURS.toDays(24));
    System.out.println(TimeUnit.DAYS.toHours(400_000_000_000_000_000L));
1
9223372036854775807

Выглядит правильно, не так ли? Это не так! По двум причинам:

  1. День не всегда 24 часа. Когда Чили переходит со стандартного времени на летнее время (DST) или наоборот, день составляет 23 или 25 часов.
  2. Преобразование не сообщает о переполнении long. Последнее преобразование переполняется. TimeUnit молчаливо дает нам ближайшее значение, которое может вписаться в long, в этом случае значение Long.MAX_VALUE.

Когда вы знаете, что делаете, и знаете, что ваши конверсии нене переполняйте, вы можете использовать его. Я также делаю большую часть моей математики int без проверки переполнения. java.time предлагает приятную беседу, которая проверяет переполнение:

    System.out.println(Duration.ofDays(400_000_000_000_000_000L).toHours());

Исключение в потоке "main" java.lang.ArithmeticException: длительное переполнение

Я даженайти этот код немного более читабельным, чем код TimeUnit.

...