2016-09-12 2 views
5

Я запутался во времени во время java. Я так долго работал в предположении, что если временная метка указана как время zulu, java позаботится о смещении относительно местного времени.Путаница с Java Разбор по времени UTC

Для иллюстрации. Я в настоящее время в 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 

Что является правильным.

Поэтому вопрос (ы):

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

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

ответ

5

Вы недопонимаете цель 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()); 
+0

Ваш пример выглядит так, как если бы это было мгновенное обсуждение моего примера 3. Вы правы, я неправильно понял, что означает LocalDateTime. ughh .. timezones :) Спасибо – pandaadb

+0

Ах, поэтому ZonedDateTime распознает часовой пояс как «Z», который он интерпретирует как UTC автоматически (просто то, что я хочу) - это правильно? – pandaadb

+0

@pandaadb Да, это, вероятно, еще один способ для написания этого. –

3

Т.Л., др

Пример:

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

2016-09-12T14: 15: 17,309 + 01: 00 [Europe/London]

Run in IdeOne.com.

Подробности

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

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

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

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

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

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

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

О java.time

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

Проект Joda-Time, теперь в maintenance mode, советует перейти на java.time.

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

Где получить классы java.time?

  • Java SE 8 и SE 9, а затем
    • Встроенный.
    • Часть стандартного Java API с объединенной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и SE 7
    • Большая часть функциональности java.time будет обратно портирован на Java 6 & 7 в ThreeTen-Backport.
  • Android
    • Проект ThreeTenABP адаптирует ThreeTen-Backport (как упоминалось выше) для Android специально.
    • См. How to use….

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