Реальная причина вашей проблемы - обработка знаков . Ваш ввод не имеет знака, но элемент синтаксического анализа "yyyy" является жадным для анализа максимально возможного количества цифр и ожидает положительный знак, поскольку найдено более четырех цифр.
Мой анализ был сделан двумя разными способами:
отладка (чтобы увидеть, что действительно стоит за непонятным сообщением об ошибке)
моделирование поведения в другом движке синтаксического анализа на основе моей библиотеки Time4J для получения лучшего сообщения об ошибке:
ChronoFormatter<LocalDate> cf =
ChronoFormatter
.ofPattern(
"yyyy[MM]",
PatternType.THREETEN,
Locale.ROOT,
PlainDate.axis(TemporalType.LOCAL_DATE)
)
.withDefault(PlainDate.MONTH_AS_NUMBER, 1)
.withDefault(PlainDate.DAY_OF_MONTH, 1)
.with(Leniency.STRICT);
System.out.println(cf.parse("201411"));
// java.text.ParseException: Positive sign must be present for big number.
Вы можете обойти проблему, указав строителю всегда использовать только четыре цифры года:
DateTimeFormatter parser =
new DateTimeFormatterBuilder()
.appendValue(ChronoField.YEAR, 4)
.optionalStart()
.appendPattern("MM[dd]")
.optionalEnd()
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
.toFormatter();
System.out.println(parser.parse("2014", LocalDate::from)); // 2014-01-01
System.out.println(parser.parse("201411", LocalDate::from)); // 2014-11-01
System.out.println(parser.parse("20141130", LocalDate::from)); // 2014-11-30
Обратите внимание на расположение элементов по умолчанию в компоновщике. Они вызываются не в начале, а в конце, потому что обработка элементов по умолчанию, к сожалению, чувствительна к положению в java.time
. И я также добавил дополнительный необязательный раздел для дня месяца в первом необязательном разделе. Это решение кажется мне более чистым, вместо того, чтобы использовать последовательность из 3 необязательных секций, как было предложено Данилой Жаренковым, потому что последний также может анализировать совершенно разные входные данные со многими другими цифрами (возможное неправильное использование необязательных секций в качестве замены или-паттернов, особенно в снисходительном порядке). синтаксический анализ).
О позиционно-чувствительном поведении элементов по умолчанию здесь цитата из API-документации :
Во время синтаксического анализа проверяется текущее состояние анализа. Если
указанное поле не имеет связанного значения, потому что оно не было
в этот момент успешно проанализирован, то указанное значение
впрыскивается в результат разбора. Инъекция немедленная, поэтому
пара поле-значение будет видима для любых последующих элементов в
форматировщик. Таким образом, этот метод обычно вызывается в конце
строитель.
Кстати: в моей библиотеке Time4J я также могу определить реальных или-образцов , используя символ "|" и затем создайте этот форматер:
ChronoFormatter<LocalDate> cf =
ChronoFormatter
.ofPattern(
"yyyyMMdd|yyyyMM|yyyy",
PatternType.CLDR,
Locale.ROOT,
PlainDate.axis(TemporalType.LOCAL_DATE)
)
.withDefault(PlainDate.MONTH_AS_NUMBER, 1)
.withDefault(PlainDate.DAY_OF_MONTH, 1)
.with(Leniency.STRICT);