Java: DateTimeFormatter не может проанализировать строку времени, когда все секунды и миллисекунды равны 0?

В основном, я использую следующий код для разбора строки как LocalDateTime, которая работает в большинстве случаев.

DateTimeFormatter dtformatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");

Однако я сталкиваюсь со случаями, когда секунды и миллисекунды 00000 и это когда синтаксический анализатор не удается и распечатать LocalDateTime2018-03-01T09:16 вместо 2018-03-01T09:16:00.000,

System.out.println(LocalDateTime.parse("20180301091600000",dtformatter));

(Обратите внимание, что в моем коде, я должен проанализировать строку как LocalDateTime, сделайте некоторое сравнение и затем в конце напечатайте LocalDateTime в CSV)

Как я могу это исправить, чтобы сделать его печатным 2018-03-01T09:16:00.000 вместо 2018-03-01T09:16?

К вашему сведению, я использую jdk10.

3 ответа

Решение

Я не уверен, почему это не работает, кажется, это ошибка, потому что, когда я использую:

20180301091600001        result is      2018-03-01T09:16:00.001
----------------^                       -----------------^^^^^^

Также еще один тест:

2018030100000000         result is      2018-03-01T00:00
--------^^^-----                        -----------^^^^^^^^^^^

Кажется, что парсер игнорирует секунды и миллисекунды, когда он равен нулю, почему?

Полное объяснение почему?, в ответе Василия Бурка.


Решение

Вот быстрое исправление, где вы можете использовать другой форматтер, как это:

var result = LocalDateTime.parse("20180301091600000", dtformatter)
                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss:SSS"));

Выход

2018-03-01T09:16:00:000

ТЛ; др

где секунды и миллисекунды равны 00000, и это когда происходит сбой синтаксического анализатора

Нет, парсер успешен. Ваша проблема с генерацией строки, а не с ее разбором.

По умолчанию DateTimeFormatter подавляет нулевые значения в секундах и доли секунды, как задокументировано.

Особенность, а не ошибка

Ваша проблема не в разборе, а в генерации строки после разбора. Имейте в виду, что текстовое представление объекта даты и времени отличается от объекта. Другими словами, объект даты и времени не имеет "формата".

[Строка] -> parse -> [LocalDateTime] -> toString -> [Строка]

Документация для LocalDateTime::toString ясно говорит, что кратчайшие возможные варианты форматирования будут использоваться при обнаружении нулевых значений в наименее значимых частях. Цитировать:

Выходные данные будут в одном из следующих форматов ISO-8601:

уууу-ММ-dd'T'HH: мм

уууу-ММ-dd'T'HH: мм: сс

уууу-ММ-dd'T'HH: мм: СС.ссс

уууу-ММ-dd'T'HH: мм: ss.SSSSSS

уууу-ММ-dd'T'HH: мм: ss.SSSSSSSSS

Используемый формат будет самым коротким, который выводит полное значение времени, когда пропущенные части подразумеваются равными нулю.

Примеры

Относительно двух примеров, показанных в принятом Ответе YCF_L

20180301091600001 - 2018-03-01T09:16:00.001

В этом примере наименее значимая часть (миллисекунда) имеет ненулевое значение, поэтому она представлена ​​в результате.

2018030100000000 результат - 2018-03-01T00:00

В этом примере наименее значимые части часа, минуты, секунды, миллисекунды, микросекунды и наносекунды равны нулю. Таким образом, их отображение подавляется, за исключением часов и минут, поскольку документация обещает, что год-минута всегда отображается.

Так что оба ваших примера работают как задокументировано; особенность, а не ошибка.

Решение

Решение состоит в том, чтобы не использовать форматтер по умолчанию, предоставленный в toString метод. Вместо этого используйте другой форматер. Например, используйте тот же пользовательский форматер, который вы определили для анализа.

DateTimeFormatter f = DateTimeFormatter.ofPattern( "yyyyMMddHHmmssSSS" );
LocalDateTime ldt = LocalDateTime.parse( "20180301091600000" , f );

String outputDefault = ldt.toString();
String outputCustom = ldt.format( f );

Дамп на консоль.

System.out.println( "outputDefault: " + outputDefault );
System.out.println( "outputCustom: " + outputCustom );

outputDefault: 2018-03-01T09: 16

outputCustom: 20180301091600000

Вопрос задает:

Как я могу исправить это, чтобы он печатал 2018-03-01T09:16:00.000 вместо 2018-03-01T09:16?

Укажите пользовательский форматер вместо стандартного.

DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss:SSS") ; 
String output = ldt.format( f ) ;

Но имейте в виду, что ваша сгенерированная строка будет подавлять отображение любых микросекунд или наносекунд в LocalDateTime объект.

@BasilBourque У меня есть еще вопрос к вам, ответ выше

Когда мы анализируем это в OffsetDateTime, у меня есть дата «2023-12-10T00:00:00.000». Анализируемый объект OffsetDateTime никогда не имеет секунд и наносекунд. можем ли мы как-нибудь добавить секунды и нано в объект OffsetDateTime? Пожалуйста, ознакомьтесь с прикрепленным фрагментом кода и информацией об отладке.

Другие вопросы по тегам