Java 8 DateTimeFormatter разбор необязательных разделов
Мне нужно разобрать дату-время как строки, приходящие в двух разных форматах:
- 19861221235959Z
- 1986-12-21T23: 59: 59Z
Следующий шаблон dateTimeFormatter правильно анализирует строки даты первого типа
DateTimeFormatter.ofPattern ("uuuuMMddHHmmss[,S][.S]X")
Но терпит неудачу на втором, так как тире, двоеточия и Т не ожидаются.
Я попытался использовать дополнительные разделы следующим образом:
DateTimeFormatter.ofPattern ("uuuu[-]MM[-]dd['T']HH[:]mm[:]ss[,S][.S]X")
Неожиданно, это разбирает второй тип строк даты (тот, который с тире), но не первый вид, бросая a
java.time.format.DateTimeParseException: Text '19861221235959Z' could not be parsed at index 0
Как будто необязательные разделы не оцениваются как необязательные...
4 ответов:
Как заявил Питер в комментариях, проблема заключается в том, что ваш шаблон рассматривает всю строку как год. Вы можете использовать
.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();
DateTimeFormatter, основанный на шаблонах, недостаточно умен, чтобы обрабатывать как необязательный раздел, так и возможность иметь два числовых поля без разделения. Когда вам нужно, чтобы ваши числовые поля были без разделителя, без вопросов, тогда шаблон понимает, что Изменение буквы шаблона с u на M означает, что ему нужно считать цифры, чтобы знать, какая цифра является частью каких полей. Но когда это не является определенностью, тогда паттерн не пытается этого сделать. Он видит одну цифру поле описано полностью и не сразу сопровождается другими числовыми полями. Поэтому нет смысла считать цифры. Все цифры являются частью поля, которое должно быть представлено здесь.
Чтобы сделать это, вы не должны пытаться построить свой DateTimeFormatter с шаблоном, а с помощью конструктора. Черпайте вдохновение у
DateTimeFormatter.BASIC_ISO_DATEи других, находящихся поблизости.
Это не ясно из документации, но я предполагаю, что происходит следующее.
При использовании
uuuuMMddHHmmssв строке шаблона форматирования модуль форматирования может легко увидеть, что существует несколько смежных числовых полей, и поэтому использует ширину поля для разделения полей. Первые 4 цифры означают год, и так далее.Когда вместо этого вы используете
uuuu[-]MM[-]dd['T']HH[:]mm[:]ss, форматер не воспринимает его как соседние числовые поля. Я согласен с замечаниями Питера Лоури что это, следовательно, занимает более длительный цикл цифр для года и в конце концов переполняет максимальный год (999999999) и выбрасывает исключение.Решение? Пожалуйста, обратитесь кответу Майкла .
На первый взгляд ваш второй формат должен работать в обоих случаях. Кстати, мне любопытно, почему вы использовали " u "вместо" y " в течение года. Поэтому я бы попробовал использовать "y", просто чтобы посмотреть, имеет ли это значение. Но в целом вы касаетесь интересного момента-как разобрать дату из неизвестного формата (представьте, что вместо 2 возможных форматов вы имеете дело с неизвестным количеством форматов). Я действительно однажды написал такой парсер. Идея, к которой я привык решение этой задачи описано в моей статье Java 8 java.пакет time: разбор любой строки на дату . Возможно, Вам эта идея покажется полезной. Короче говоря, идея состоит в том, чтобы иметь внешний файл, который содержит все поддерживаемые форматы в нем и попытаться применить каждый формат один за другим, пока он не работает.
Comments