Путаница с Java Time parsing UTC

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

для иллюстрации. В настоящее время я нахожусь в BST, который имеет смещение UTC +1. Имея это в виду, я ожидал бы этого зулусского времени:

2016-09-12T13:15:17.309Z

на

2016-09-12T14:15:17.309 

LocalDateTime после его анализа. Это потому, что мое системное время по умолчанию установлено в BST и вышеуказанная метка времени (время zulu) указывает, что это время UTC.

вместо этого, однако, рассмотрим этот пример:

        String ts = "2016-09-12T13:15:17.309Z";
        LocalDateTime parse = LocalDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME);
        System.out.println(parse);

это будет напечатано:

2016-09-12T13:15:17.309

таким образом, метка времени, анализируемая как LocalDateTime, не распознается как время UTC и вместо этого обрабатывается как локальное время напрямую. Поэтому я подумал, что, возможно, мне нужно проанализировать его как ZonedDateTime и преобразовать его в LocalDateTime специально, чтобы получить правильное местное время. С этим тест:

        String ts = "2016-09-12T13:15:17.309Z";
        ZonedDateTime parse = ZonedDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME);
        System.out.println(parse);
        System.out.println(parse.toLocalDateTime());

Я получаю выходы:

2016-09-12T13:15:17.309Z
2016-09-12T13:15:17.309

одинаковый вывод для обеих дат.

единственный способ правильно разобрать это, что я мог найти, это:

    String ts = "2016-09-12T13:15:17.309Z";
    Instant instant = Instant.parse(ts); // parses UTC
    LocalDateTime ofInstant = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    System.out.println(instant);
    System.out.println(ofInstant);

печатается:

2016-09-12T13:15:17.309Z
2016-09-12T14:15:17.309

что верно.

Итак, вопрос(ы):

  • не стоит времени Java узнать время UTC и разобрать его на правильный системы по умолчанию?
  • как я могу использовать LocalDateTime#parse подход чтобы получить правильный результат?
  • должен ли я использовать Instant для всего сейчас и отказаться от разбора?

проблема в том, что jersey/jacksonмодули времени java анализируют временные метки, используя формат ISO и обычный LocalDateTime#parse методы. Я понял, что мои времена не прочь, так как они рассматриваются как LocalTime хотя на самом деле они находятся в зулусском времени.

2 ответов


вы неправильно поняли цель LocalDateTime.

чтобы процитировать документацию класса:

дата-время без часового пояса в календарной системе ISO-8601, например {@code 2007-12-03T10:15:30}.

...

этот класс не хранит и не представляет часовой пояс. Это описание момента, как на дни рождения, в сочетании с местным временем, как видно на настенные часы. Он не может представлять мгновенный на линии времени без дополнительной информации, такой как смещение или часовой пояс.

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

поэтому каждое преобразование просто удаляет часовой пояс.

так что для ваших целей вам нужен ZonedDateTime С ZoneId.systemDefault() как вы уже использовали в своей третий пример.

для вашего второго примера это может быть:

String ts = "2016-09-12T13:15:17.309Z";
ZonedDateTime parse = 
    ZonedDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME)
        .withZoneSameInstant(ZoneId.systemDefault());
System.out.println(parse);
System.out.println(parse.toLocalDateTime());

tl; dr

пример:

Instant.parse( "2016-09-12T13:15:17.309Z" )
       .atZone( ZoneId.of( "Europe/London" ) )
       .toString();

2016-09-12T14:15:17.309+01:00[Европа/Лондон]

Run in IdeOne.com.

подробности

на ответ Krüske является правильным. Вы неправильно поймите значение LocalDateTime класса. Это не представляют дату-время конкретной местности. Как раз наоборот, это делает не представляют собой фактический момент вообще.

предлагаю подумать о Instant как ваш основной класс строительного блока в java.время. The Instant класс представляет момент на временной шкале в UTC с разрешением наносекунд (до девяти (9) знаков после запятой фракция.)

входная строка соответствует формату ISO 8601, используемому по умолчанию в Instant класс как для синтаксического анализа, так и для генерации строковых представлений. The Z на конце сокращенно от Zulu и означает UTC. Нет необходимости указывать шаблон форматирования.

Instant instant = Instant.parse( "2016-09-12T13:15:17.309Z" );

как программист вы должны научиться думать и работать в UTC в первую очередь. Забудь о своем часовом поясе. Подумайте о UTC как о единственном истинном времени. Применить часовой пояс как вариацию и только как необходимый.

указать правильное название часового пояса в формате continent/region, например America/Montreal, Africa/Casablanca или Pacific/Auckland. Никогда не используйте аббревиатуру из 3-4 букв, такую как BST или EST или IST поскольку они не являются истинными часовыми поясами, не стандартизированы и даже не уникальны(!). Если BST вы имели в виду британское летнее время, тогда фактическое название часового пояса было бы Europe/London. Ява.классы времени будут определять, как отрегулировать для всех аномалий включая летнее время (DST).

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

о java.время

на java.время framework встроен в Java 8 и более поздние версии. Эти классы вытесняют беспокойных старых наследие классы даты и времени, такие как java.util.Date, Calendar, & SimpleDateFormat.

на Joda Времени, теперь ремонт режим, советует миграцию на java.время.

чтобы узнать больше, см. В Oracle Учебник. И search Stack Overflow для многих примеров и объяснений. Спецификация JSR 310.

где получить java.время занятий?

  • Java SE 8 и SE 9 и позже
    • встроенный.
    • часть стандартного Java API с комплектной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и SE 7
    • большая часть java.функциональность времени обратно портирована на Java 6 & 7 в ThreeTen-Backport.
  • Android

на ThreeTen-Extra проект расширяет java.время с дополнительными занятиями. Этот проект является испытательной площадкой для возможных будущих дополнений к java.время. Вы можете найти некоторые полезные классы, такие как Interval, YearWeek, YearQuarter и больше.