Java Instant.разбор на дату java 8

#java #time #kml #datetime-parsing #java-time

#java #время #kml #datetime-синтаксический анализ #java-time

Вопрос:

У меня есть несколько устаревших документов KML, которые включают запись с отметкой времени. Почему приведенная ниже дата недопустима при использовании Instant для разбора? Предполагается, что оба метода анализируют даты в формате ISO 8601.

Строка dateString = «2017-12-04T08:06:60Z»

Используя

 java.time.Instant.parse(dateString)
  

выдает ошибку

 "DateTimeParseException Text 2017-12-04T08:06:60Z could not be parsed at index 0."
  

Однако при использовании

 Date myDate =   javax.xml.bind.DatatypeConverter.parseDateTime( dateString )
  

myDate проанализирован правильно….

Комментарии:

1. 60 — это недопустимое количество секунд, не так ли? Кроме того, класс java.util.Calendar по умолчанию является снисходительным, поэтому я предполагаю, что он принимает 60 секунд.

2.Это может быть на високосную секунду. Но я не думаю java.time , что поддерживает високосные секунды. (И я не верю, что это допустимая високосная секунда.)

Ответ №1:

  1. 60 секунды — это недопустимое время. Это означает, что это недопустимо 2017-12-04T08:06:60Z , если бы это было 60 секунд, то минута должна была увеличиться, и ваше время было бы 2017-12-04T08:07:00Z
  2. Использование действительной даты и затем разбор строки будут работать просто отлично:

     String date = "2017-12-04T08:07:00Z";
    System.out.println(Instant.parse(date));
      

Также java.time игнорирует високосные секунды. Из документов:

Реализации временной шкалы Java с использованием API JSR-310 не требуются для предоставления каких-либо часов с точностью до секунды или которые выполняются монотонно или плавно. Поэтому реализации не требуются для фактического выполнения нарастания UTC-SLS или для того, чтобы иным образом учитывать високосные секунды. Однако JSR-310 требует, чтобы реализации документировали подход, который они используют при определении часов, представляющих текущий момент. Смотрите Clock для получения подробной информации о доступных часах.

Комментарии:

1. «60 секунд — это недопустимое время» — ну, это все зависит от вашего представления о високосных секундах. Но я не думаю, что эта конкретная дата / время действительны, даже если вы включаете високосные секунды, поскольку это не было временем, когда наблюдалась високосная секунда.

2. я понял тебя … но, похоже, что наличие 60Z допустимо в IISO 8601 и, следовательно, javax.xml.bind. DatatypeConverter работает и не выдает исключение… и автоматически увеличивается до 7:00Z.

3. Нет необходимости использовать определенный DateTimeFormatter для этого шаблон — Instant.parse подходит для значений ISO-8601 со смещением зоны «Z».

4. @JonSkeet: Точка зрения принята. Спасибо.

5. DatatypeConverter автоматически увеличивает date…to 2017-12-04T08:07:00Z … ок. я обрабатываю KML, поэтому не могу скорректировать данные, поэтому придется продолжать использовать этот класс.

Ответ №2:

Принятый ответ в порядке. Мне нужно добавить только две вещи:

  1. Вы можете проанализировать строку с недопустимым вторым значением 60, используя ResolverStyle.LENIENT .
  2. Поскольку Джон Скит в комментарии упомянул возможную високосную секунду: это недопустимая високосная секунда. java.time поддерживает синтаксический анализ (допустимой) високосной секунды.

Разбор вашей строки

     DateTimeFormatter lenientFormatter
            = DateTimeFormatter.ISO_OFFSET_DATE_TIME
                    .withResolverStyle(ResolverStyle.LENIENT);
    String dateString = "2018-12-04T08:06:60Z";
    Instant myInstant = lenientFormatter.parse(dateString, Instant::from);
    System.out.println(myInstant);
  

Вывод:

2018-12-04T08:07:00Z

Таким образом, избыточное второе значение 60 было преобразовано в целую минуту.

Кстати, javax.xml.bind.DatatypeConverter.parseDateTime выполняется синтаксический анализ в a Calendar (не a Date ), поэтому возвращаемый объект фактически может содержать второе значение 60. Кажется, что обычно он принимает второе значение 60, но выдает исключение на 61.

Анализ допустимой високосной секунды

Это никоим образом не отвечает на ваш вопрос, но я подумал, что это может быть полезно для будущих читателей. Високосная секунда всегда является последней секундой дня, поэтому 23:59:60. Instant Не может содержать это значение, но вы можете запросить, было ли оно проанализировано. Поддерживается через DateTimeFormatterBuilder.appendInstant(), и DateTimeFormatter.parsedLeapSecond() .

     DateTimeFormatter leapSecondFormatter = new DateTimeFormatterBuilder()
            .appendInstant()
            .toFormatter();
    Instant myInstant
            = leapSecondFormatter.parse("2018-12-04T23:59:60Z", Instant::from);
    System.out.println(myInstant);

    TemporalAccessor parsed = leapSecondFormatter.parse("2018-12-04T23:59:60Z");
    System.out.println("Instant: "   parsed.query(Instant::from));
    System.out.println("Was a leap second parsed? "
              parsed.query(DateTimeFormatter.parsedLeapSecond()));
  

Вывод:

 2018-12-04T23:59:59Z
Instant: 2018-12-04T23:59:59Z
Was a leap second parsed? true
  

Я не знаю, почему это должно было быть таким сложным, но это работает.

Ссылка: Документация DateTimeFormatter.parsedLeapSecond