Java 8 DateTimeFormatter разбирает необязательные разделы - PullRequest
0 голосов
/ 04 июля 2018

Мне нужно проанализировать дату и время как строки, имеющие два разных формата:

  • 19861221235959Z
  • 1986-12-21T23: 59: 59Z

Следующий шаблон dateTimeFormatter правильно анализирует строки данных первого типа

DateTimeFormatter.ofPattern ("uuuuMMddHHmmss[,S][.S]X")

, но не на втором, так как тире, двоеточий и T не ожидается.

Я пытался использовать дополнительные разделы следующим образом:

DateTimeFormatter.ofPattern ("uuuu[-]MM[-]dd['T']HH[:]mm[:]ss[,S][.S]X")

Неожиданно при синтаксическом анализе строки даты второго типа (с черточками), но не первого, выдается

java.time.format.DateTimeParseException: Text '19861221235959Z' could not be parsed at index 0

Как будто дополнительные секции не оцениваются как необязательные ...

Ответы [ 4 ]

0 голосов
/ 04 июля 2018

Как сказал Питер в комментариях, проблема в том, что ваш шаблон рассматривает всю строку как год. Вы можете использовать .appendValue(ChronoField.YEAR, 4), чтобы ограничить его четырьмя символами:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    .appendValue(ChronoField.YEAR, 4)
    .appendPattern("[-]MM[-]dd['T']HH[:]mm[:]ss[,S][.S]X")
    .toFormatter();

Это правильно обрабатывает оба ваших примера.

Если вам хочется быть еще более многословным, вы можете сделать:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    .appendValue(ChronoField.YEAR, 4)
    .optionalStart().appendLiteral('-').optionalEnd()
    .appendPattern("MM")
    .optionalStart().appendLiteral('-').optionalEnd()
    .appendPattern("dd")
    .optionalStart().appendLiteral('T').optionalEnd()
    .appendPattern("HH")
    .optionalStart().appendLiteral(':').optionalEnd()
    .appendPattern("mm")
    .optionalStart().appendLiteral(':').optionalEnd()
    .appendPattern("ss")
    .optionalStart().appendPattern("X").optionalEnd()
    .toFormatter();
0 голосов
/ 04 июля 2018

На первый взгляд ваш второй формат должен работать в обоих случаях. Не уверен, почему это не так. Кстати, мне любопытно, почему вы использовали «у», а не «у» в течение года. Так что я бы попробовал использовать «у», чтобы посмотреть, будет ли это иметь значение. Но в целом вы затрагиваете интересный момент - как разобрать дату из неизвестного формата (представьте, что вместо 2 возможных форматов вы имеете дело с неизвестным количеством форматов). Я действительно однажды написал такой парсер. Идея, которую я использовал для решения этой проблемы, описана в моей статье Java 8 пакет java.time: парсинг любой строки на сегодняшний день . Вы можете найти эту идею полезной. Короче говоря, идея состоит в том, чтобы иметь внешний файл, в котором содержатся все поддерживаемые форматы, и пытаться применять каждый формат по одному, пока не сработает.

0 голосов
/ 04 июля 2018

DateTimeFormatter, основанный на шаблонах, недостаточно умен, чтобы обрабатывать как необязательный раздел, так и возможность иметь два числовых поля без разделения. Когда вам нужно, чтобы ваши числовые поля были без разделителя, без вопросов, тогда шаблон понимает, что изменение буквы шаблона с u на M означает, что ему нужно посчитать цифры, чтобы узнать, какая цифра является частью каких полей. Но когда это не определенность, то шаблон не пытается это сделать. Он видит одно числовое поле, описанное полностью, а не сразу, а затем другие числовые поля. Следовательно, нет оснований считать цифры. Все цифры являются частью поля, которое должно быть представлено здесь.

Чтобы сделать это, вы не должны пытаться построить свой DateTimeFormatter с шаблоном, а скорее с помощью Builder. Получите вдохновение от DateTimeFormatter.BASIC_ISO_DATE и других поблизости.

0 голосов
/ 04 июля 2018

Из документации не ясно, но я предполагаю, что происходит следующее.

Когда вы используете uuuuMMddHHmmss в строке шаблона формата, средство форматирования может легко увидеть, что есть несколько смежных числовых полей, и, следовательно, использует ширину полей для разделения полей. Первые 4 цифры означают год и т. Д.

Когда вместо этого вы используете uuuu[-]MM[-]dd['T']HH[:]mm[:]ss, средство форматирования не воспринимает его как смежные числовые поля. Я согласен с замечаниями Питера Лоури о том, что, следовательно, для года требуется более длинный ряд цифр, и в конце он переполняет максимальный год (999999999) и выдает исключение.

Решение? Пожалуйста, обратитесь к ответу Михаила .

...