Joda Time to Java Time Migration показывает другой результат при миграции - PullRequest
1 голос
/ 27 марта 2020

Учитывая следующий код

public static void main(String[] args) {
     org.joda.time.format.DateTimeFormatter _timestampFomatNYCJoda = org.joda.time.format.DateTimeFormat.forPattern("yyyyMMdd HHmmss.SSS").withZone(DateTimeZone.forID("America/New_York"));
     DateTimeFormatter _timestampFomatNYC = DateTimeFormatter.ofPattern("yyyyMMdd HHmmss.SSS").withZone(ZoneId.of("America/New_York"));
     LocalDateTime localDateTime = LocalDateTime.now();
     org.joda.time.LocalDateTime jodaLocalDateTime = new org.joda.time.LocalDateTime();
     System.out.println("System Time " + new Date());
     System.out.println("Java Version " +  localDateTime.format(_timestampFomatNYC));
     System.out.println("Joda Version " +  _timestampFomatNYCJoda.print(jodaLocalDateTime.toDateTime(DateTimeZone.UTC)));
} 

Почему Java версия и версия Joda не совпадают? Я запускаю это на часах IST.

Ниже вывод

System Time Fri Mar 27 17:01:33 IST 2020
Java Version 20200327 170133.933
Joda Version 20200327 130133.938

1 Ответ

2 голосов
/ 27 марта 2020

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

Joda-Time

В Joda-Time DateTimeFormatter.withZone() предоставляет форматтер с зоной переопределения , то есть зона, которая будет всегда , будет использоваться для форматирования даты и времени. Другими словами, любая дата и время будут преобразованы в эту зону для печати. Документация гласит:

При печати эта зона будет использоваться вместо зоны вместо даты и времени, которые в противном случае использовались бы.

Когда вы делаете new org.joda.time.LocalDateTime() , вы получаете LocalDateTime, представляющий текущую дату и время в вашем часовом поясе по умолчанию. Local в некоторых именах классов означает без часового пояса или смещения от UT C. Я полагаю, что у вас должно быть значение, равное 2020-03-27T17:01:33.938.

Очевидно, что, когда вы форматируете LocalDateTime с помощью средства форматирования с зоной переопределения, форматировщик предполагает, что ваш LocalDateTime равен в UT C (который у вас нет) и конвертирует его оттуда, в вашем случае в часовой пояс America / New_York. Поскольку летнее время (DST) действует в Нью-Йорке, смещение составляет -04: 00, поэтому 17:01 становится 13: 01.

Это неверный результат. Когда время в вашем часовом поясе равно 17:01, это не 17:01 UT C, поэтому преобразование основано на ложной предпосылке. В Нью-Йорке также не 13:01, поэтому конвертированный результат показывает al ie.

java .time

с java. Установка времени для зоны переопределения в форматере работает аналогично для форматирования, но с разницей, которая имеет значение здесь: зона переопределения используется только при печати объекта даты и времени, который идентифицирует момент (момент времени). Из документов:

При форматировании, если временный объект содержит момент, он будет преобразован в зонированную дату-время с использованием зоны переопределения. Является ли временное значение моментом, определяется путем запроса поля INSTANT_SECONDS. Если вход имеет хронологию, он будет сохранен, если не переопределен. Если у входа нет хронологии, такой как Мгновенная, будет использоваться хронология ISO.

… Во всех других случаях зона переопределения добавляется к временной, заменяя любую предыдущую зону, но без изменения дата / время.

Опять LocalDateTime.now() показывает текущую дату и время дня (на несколько миллисекунд раньше, чем запрос через Joda-Time), 2020-03-27T17:01:33.933. Local по-прежнему означает без смещения или часового пояса.

Поскольку ваш LocalDateTIme не имеет смещения или часового пояса, он не может определить однозначный момент времени, мгновение. Поэтому при форматировании ни дата, ни время суток не меняются. А поскольку шаблон формата не содержит часовой пояс или смещение, ни один из них не печатается. Таким образом, вы просто получаете дату и время в своем часовом поясе (не в Нью-Йорке), 20200327 170133.933.

Чтобы получить дату и время в часовом поясе Нью-Йорка

    DateTimeFormatter timestampFormat
            = DateTimeFormatter.ofPattern("yyyyMMdd HHmmss.SSS");
    ZonedDateTime timeInNy = ZonedDateTime.now(ZoneId.of("America/New_York"));
    System.out.println(timeInNy.format(timestampFormat));

Когда я только что запустил этот код, вывод был:

20200327 122359.683

Ссылки на документацию

...