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, и если это известная проблема, каково возможное обходное решение для нее.
Спасибо заранее.
Ответы
Ответ 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, чтобы избежать путаницы для пользователя.