SimpleDateFormat - странный результат при разборе даты - PullRequest
0 голосов
/ 04 декабря 2018

В настоящее время я в растерянности из-за следующего простого использования SimpleDateFormatter:

 import java.text.ParseException;
 import java.text.SimpleDateFormat;

 public static void main(String[] args) throws ParseException {
    System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX").parse("2018-12-04T22:22:01+1000"));
 }

Я запускаю этот пример с JDK 1.8.0_192.

Мой компьютер находитсяв CET (+1000), поэтому часовой пояс равен.Таким образом, ожидаемый результат будет:

вт дек 04 22:22:01 CET 2018

Но я получаю следующий вывод:

Вт дек 04 13:22:01 CET 2018

У кого-нибудь есть идея, что здесь происходит?

Ответы [ 2 ]

0 голосов
/ 05 декабря 2018

tl; dr

Ваша первоначальная проблема была опечаткой +1000 против +0100.Тем не менее, все советы, приведенные ниже, остаются в силе.Вы используете ужасные старые классы, которых следует избегать.

OffsetDateTime.parse( 
    "2018-12-04T22:22:01+1000" ,   // Input in standard ISO 8601, with the COLON omitted from the offset as allowed by the standard but breaking some libraries such as `OffsetDateTime.parse`. 
    DateTimeFormatter.ofPattern( 
        "uuuu-MM-dd'T'HH:mm:ssX" 
    )
)                                  // Returns a `OffsetDateTime` object.
.toInstant()                       // Adjust into UTC. Returns an `Instant` object. Same moment, different wall-clock time.
.atZone(                           // Adjust from UTC to some time zone. Same moment, different wall-clock time.
    ZoneId.of( "Europe/Brussels" ) 
)                                  // Returns a `ZonedDateTime` object.
.toString()                        // Generate text representing this `ZonedDateTime` object in standard ISO 8601 format but wisely extending the standard by appending the name of the time zone in square brackets.

18-12-04T13: 22: 01 + 01: 00 [Европа / Брюссель]

Избегайте устаревших классов даты и времени

Вы используете ужасные старые классы даты и времени, связанные с ранними версиями Java.Шестнадцать лет тому назад классы java.time .

Использовали надлежащие часовые пояса

FYI, CET не является реальным часовым поясом.

Укажите собственное имя часового пояса в формате continent/region, например America/Montreal, Africa/Casablanca или Pacific/Auckland.Никогда не используйте 2-4 буквенные сокращения, такие как EST или IST, так как они не истинные часовые пояса, не стандартизированы и даже не уникальны (!).

ZoneId z = ZoneId.of( "America/Montreal" ) ;  

Вы, вероятно, имеете в виду часовой пояс, например Europe/Brussels, Europe/Paris, Europe/Berlin, Africa/Tunis или Europe/Oslo.

ISO 8601

Ваша строка ввода 2018-12-04T22:22:01+1000 в стандартном формате, определенном ISO 8601 .

Последняя часть +1000 представляет собой смещение от UTC , что означает момент на десять часов раньше UTC.Таким образом, это значение предназначалось для настенного времени, используемого людьми в каком-либо регионе Тихого океана, например, в часовом поясе Australia/Lindeman.

Не сокращать обозначение смещения

Эта строка +1000 является сокращением смещения, опуская разделитель символов COLON между часами и минутами (и секундами, если они есть).Хотя стандарт допускает это упущение, я предлагаю всегда включать COLON: 2018-12-04T22:22:01+10:00.По моему опыту, некоторые библиотеки и протоколы ломаются при обнаружении таких строк.А включение COLON делает строку более читабельной для людей.

OffsetDateTime

Действительно, класс java.time.OffsetDateTime, предназначенный для анализа таких стандартных строк по умолчанию, имеет ошибку в этом отношении.разобрать, когда COLON опущен.Обсуждено по адресу:

Обходной путь:

OffsetDateTime odt = 
    OffsetDateTime.parse( 
        "2018-12-04T22:22:01+1000" , 
        DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ssX" )
    )
;

См. Пример кода runninglive at IdeOne.com .

odt.toString (): 2018-12-04T22: 22: 01 + 10: 00

Настройте это значение вUTC путем извлечения объекта Instant.Instant всегда в UTC по определению.

Instant instant = odt.toString() ;

instant.toString (): 2018-12-04T12: 22: 01Z

Наконец, мы можемнастроить в свой собственный приходской часовой пояс.

Под CET Я предполагаю, что вы имели в виду часовой пояс, например Europe/Paris.

ZoneId z = ZoneId.of( "Europe/Paris" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

При вызове ZonedDateTime::toString текст генерируется в стандартном формате ISO 8601, но разумно расширяетсястандарт для добавления имени часового пояса в квадратных скобках.

zdt.toString(): 2018-12-04T13:22:01+01:00[Europe/Paris]

Все три из эти объекты (odt, instant, & zdt) относятся к одному и тому же одновременномумомент , та же самая точка на временной шкале.Их единственное отличие - время настенных часов.Если бы три человека на телефонной конференции в Австралии, Франции и Исландии (всегда в UTC) одновременно смотрели вверх, чтобы прочитать текущий момент с их соответствующих часов, висящих на их локальной стене, они прочитали бы три разных значения для одного и того же одновременного момента.

Просмотреть весь этот код запустить на этой странице IdeOne.com .


О java.time

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

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

Чтобы узнать больше, см. Руководство по Oracle .И поиск переполнения стека для многих примеров и объяснений.Спецификация: 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 .

0 голосов
/ 04 декабря 2018

Вы даете ему 2018-12-04T22:22:01+1000, что составляет 2018-12-04T12:22:01 в UTC.В то время как CET на 1 час впереди UTC, вы получите час 13.

...