Подтвердить что ты не робот

Java Date timezone печатает различные временные интервалы для разных лет, обходной путь

При тестировании моего приложения у меня возникла странная проблема. Когда я помещаю дату, имеющую год до 1945 года, она меняет часовой пояс.

У меня есть эта простая программа, чтобы показать проблему.

public static void main(String[] args) {
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ");
    Calendar calendar = Calendar.getInstance();

    System.out.println("**********Before 1945");
    calendar.set(1943, Calendar.APRIL, 12, 5, 34, 12);
    System.out.println(format.format(calendar.getTime()));
    System.out.println(calendar.getTime());

    System.out.println("**********After 1945");
    calendar.set(1946, Calendar.APRIL, 12, 5, 34, 12);
    System.out.println(format.format(calendar.getTime()));
    System.out.println(calendar.getTime());
}

Выход, который я получаю, ниже: -

**********Before 1945
1943-04-12 05:34:12+0630
Mon Apr 12 05:34:12 IDT 1943

**********After 1945
1946-04-12 05:34:12+0530
Fri Apr 12 05:34:12 IST 1946

Для первого я получаю его как +0630 и IDT, а для второго я получаю +0530 и IST, которые ожидаются.

Изменить: -

Посмотрев на ответ @Elliott Frisch, я пробовал дату до 1942 года: -

calendar.set(1915, Calendar.APRIL, 12, 5, 34, 12);
System.out.println(format.format(calendar.getTime()));
System.out.println(calendar.getTime());

Выход: -

1915-04-12 05:34:12+0553
Mon Apr 12 05:34:12 IST 1915

Здесь снова говорится IST, но показывает +0553. Не должно быть +0530.

Просто для сравнения, я пробовал то же самое в javascript: -

new Date("1946-04-12 05:34:12") //prints Fri Apr 12 1946 05:34:12 GMT+0530 (IST)
new Date("1943-04-12 05:34:12") //prints Fri Apr 12 1943 05:34:12 GMT+0530 (IST)
new Date("1915-04-12 05:34:12") //prints Mon Apr 12 1915 05:34:12 GMT+0530 (IST)

Что отлично работает. Я хочу знать, почему на него влияет java, и если это известная проблема, каково возможное обходное решение для нее.

Спасибо заранее.

4b9b3361

Ответ 1

Вероятно, это ожидаемое поведение от Java (а не от JavaScript).

Как видно из комментария RobG, языки программирования могут поддерживать или не поддерживать исторические правила времени (например, DST и смещения временной шкалы). В вашем случае, похоже, ваша среда выполнения Java поддерживает его, тогда как время выполнения JavaScript не работает.

Список исторических часовых поясов и правил DST для Индии можно найти на timeanddate.com. Список подтверждает смещения часовых поясов ваших дат Java:

  • До 1941 года: UTC + 5: 53: 20
  • 1941: UTC + 6: 30
  • 1942: UTC + 5: 30
  • 1943-44: UTC + 6: 30
  • С 1945 года: UTC + 5: 30

Проверка ваших дат с Wolfram | Alpha подтверждает ваши сдвиги по дате UTC: 1915, 1943, 1946

Википедия предоставляет дополнительную информацию о время в Индии:

Время Калькутты официально поддерживалось как отдельный часовой пояс до 1948 года.

Время Калькутты может быть указано как UTC + 5: 54 или UTC + 5: 53: 20. Последнее соответствует вашему примеру кода.

В записи в Википедии далее сообщается, что текущий часовой пояс IST со смещением UTC + 5: 30 не был в полной мере во всей Индии до 1955 года.

Как отмеченный Эллиоттом Фришем и подтвержденный ссылкой на timeanddate.com выше, DST действовал во время Второй мировой войны. В своем комментарии к его ответу вы указываете:

- это то, как мы должны сохранять в базе данных и использовать его в приложениях, или мы используем для этого некоторое обходное решение

Я думаю, это зависит. Если вам действительно нужно точно определить даты как точки во времени, вам потребуется не зависящее от времени представление, такое как UTC или unix time (или миллисекунды с момента unix). Если вы просто работаете с локальными датами из одного и того же часового пояса, может быть достаточно простого строкового представления (например, YYYY-MM-DD hh: mm: ss).

Ответ 2

Была война . Из ссылки на Википедию Индия наблюдала ДСТ во время Второй мировой войны с 1942 по 1945 год.

Ответ 3

java.time

Избегайте использования проблемных старых классов времени, связанных с самыми ранними версиями Java. Теперь наследие, вытесненное классами java.time.

ZoneId z = ZoneId.of( "Asia/Kolkata" );  // "Asia/Calcutta"
LocalTime lt = LocalTime.of( 5 , 34 , 12 );

ZonedDateTime zdt1943 = ZonedDateTime.of( LocalDate.of( 1943 , Month.APRIL , 12 ) , lt , z );
ZonedDateTime zdt1945 = ZonedDateTime.of( LocalDate.of( 1945 , Month.APRIL , 12 ) , lt , z );
ZonedDateTime zdt1946 = ZonedDateTime.of( LocalDate.of( 1946 , Month.APRIL , 12 ) , lt , z );
ZonedDateTime zdt2016 = ZonedDateTime.of( LocalDate.of( 2016 , Month.APRIL , 12 ) , lt , z );

Дамп для консоли.

System.out.println( "zdt1943: " + zdt1943 );
System.out.println( "zdt1945: " + zdt1945 );
System.out.println( "zdt1946: " + zdt1946 );
System.out.println( "zdt2016: " + zdt2016 );

Смотрите живой код в IdeOne.com.

При запуске. Мы видим то же поведение, что и в вашем Вопросе, с offset-from-UTC шесть с половиной часов во время войны и пять и половина после. Мы получаем такое же поведение, используя Asia/Kolkata или Asia/Calcutta. В классах java.time используется tzdata, ранее известная как Olson Database.

zdt1943: 1943-04-12T05: 34: 12 + 06: 30 [Азия/Калькутта]

zdt1945: 1945-04-12T05: 34: 12 + 06: 30 [Азия/Калькутта]

zdt1946: 1946-04-12T05: 34: 12 + 05: 30 [Азия/Калькутта]

zdt2016: 2016-04-12T05: 34: 12 + 05: 30 [Азия/Калькутта]

В вопросе...

Когда я помещаю дату, имеющую год до 1945 года, она меняет часовой пояс.

Нет, это не изменит часовой пояс. Результаты говорят, что в предыдущие годы "5:34" определялось как на шесть с половиной часов раньше UTC, а в последующие годы определение стал на пять с половиной часов раньше UTC. Точно так же, как "5:34" означает восемь часов позади UTC в Сиэтле летом, но семь часов зимой, из-за Летнее время (DST) ерунда.

Но я подозреваю, что это могут быть неправильные значения; читайте дальше.

Время в Калькутте

Поведение, которое мы наблюдаем, похоже, не соответствует моему чтению этой страницы Википедии, Время в Калькутте. На этой странице описываются нечетные смещения, кроме как в час или полтора часа, например UTC+05:54, которые мы не видим ни в одном из наших соответствующих образцов кода.

Поэтому я подозреваю, что tddata не содержит эти исторические данные для Индии. Но только эти непрофессионалы догадываются; Я не историк.

Не использовать типы даты для исторических значений

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

Но мы не должны ожидать такой обработки! Знайте, что tzdata не обещает полного покрытия часовых поясов до 1970 года.

Когда вы ссылаетесь на исторические значения даты и времени, я предлагаю вам использовать просто текст, а не любой из типов данных даты и времени. Цель типов данных - проверка и расчет. Вы, вероятно, не делаете ни исторических значений. Я не могу себе представить, что вы определяете количество дней, когда счет-фактура просрочен с 1943 года.

Возможно, вам следует отредактировать свой вопрос, чтобы описать, почему вы так точно сохраняете эти исторические значения даты и времени в базе данных. Если бы вы просто экспериментировали и замечали эти проблемы, знайте, что вам не следует ожидать точной обработки времени в далеком прошлом (до 1970 года) или в далекое будущее (за несколько недель внимание политиков иногда дает о внезапных изменениях определения часовых поясов),

Результат: Попытка точно обрабатывать исторические значения даты и времени чревата различными проблемами и кажется мне бессмысленной.

каков возможный обходной путь для него

Я предлагаю использовать "локальные" значения даты и времени как текст в формате ISO 8601 без какого-либо часового пояса.

Ответ 4

Я бы рекомендовал сохранить эпоху, эквивалентную датам в базе данных. Я считаю, что независимо от дневной экономии времени, время и дата периода представляют фактическое, будь то IDT или IST. Я бы использовал пример fooobar.com/info/121336/... и преобразовал все даты в эпоху и сохранил их в БД. Я отменил логику, чтобы отобразить время даты из базы данных вместе с индикатором IDT/IST, чтобы избежать путаницы для пользователя.