Использование нового Java 8 DateTimeFormatter для строгого анализа даты
у меня простая проблема: я хочу разобрать строки Java в формате "yyyyMMdd"
строго, так что "19800229"
является допустимой датой, но "19820229"
нет. Предположим, это даты объявления из обычного григорианского календаря.
Я пытаюсь использовать новый тег java.time
пакет из JDK 8 для решения этой проблемы, но он оказывается более сложным, чем ожидалось. Мой текущий код:
private static final DateTimeFormatter FORMAT = DateTimeFormatter
.ofPattern("yyyyMMdd").withChronology(IsoChronology.INSTANCE)
.withResolverStyle(STRICT);
public static LocalDate parse(String yyyyMMdd) {
return LocalDate.parse(yyyyMMdd, FORMAT);
}
однако разбор действительной даты, такой как "19800228", производит то, что мне непонятно ошибка:
java.время.формат.DateTimeParseException: не удалось проанализировать текст '19820228': невозможно получить LocalDate от TemporalAccessor: {MonthOfYear=2, DayOfMonth=28, YearOfEra=1982},ISO типа java.время.формат.Разобран
как использовать java.time.format.DateTimeFormatter
решить простой пример?
3 ответов
я редактирую, чтобы ограничить, какая строка будет считаться допустимой, используя пользовательский форматтер, созданный с помощью DateTimeFormatterBuilder.
public class DateFormmaterTest {
static DateTimeFormatter CUSTOM_BASIC_ISO_DATE = new DateTimeFormatterBuilder()
.parseCaseInsensitive().appendValue(YEAR, 4)
.appendValue(MONTH_OF_YEAR, 2).appendValue(DAY_OF_MONTH, 2)
.optionalStart().toFormatter()
.withResolverStyle(ResolverStyle.STRICT)
.withChronology(IsoChronology.INSTANCE);
public static void main(String[] args) {
LocalDate date1 = LocalDate.parse("19800228-5000",
CUSTOM_BASIC_ISO_DATE);
System.out.println(date1);
}
}
2/29/1982 недействителен и будет бросать следующее:
Caused by: java.time.DateTimeException: Invalid date 'February 29' as '1982' is not a leap year
at java.time.LocalDate.create(LocalDate.java:429)
дата 19800228-5000 будет работать с BASIC_ISO_DATE, потому что она позволяет необязательное смещение, которое вы не хотите разрешать. Мой CUSTOM_BASIC_ISO_DATE форматер этого не позволит и выдаст следующее:
Exception in thread "main" java.time.format.DateTimeParseException: Text '19800228-5000' could not be parsed, unparsed text found at index 8.
Примечание, Если вы уверенный в длине строки, yyyyMMdd, вы всегда можете работать с подстрокой первых 8 символов, чтобы отрицать необходимость в распознавателе. Однако это две разные вещи. Распознаватель будет отмечать недопустимые форматы даты на входе, и подстрока, конечно,просто удалит дополнительные символы.
Java 8 используется uuuu
в течение года, не yyyy
. В Java 8, yyyy
означает "год эры" (BC или AD), и сообщение об ошибке жалуется, что MonthOfYear, DayOfMonth и YearOfEra недостаточно информации для построения даты, потому что эра не известна.
чтобы исправить это, используйте uuuu
в строке формата, например,DateTimeFormatter.ofPattern("uuuuMMdd")
или, если вы хотите продолжать использовать yyyy
, вы можете установить эру по умолчанию, например
private static final DateTimeFormatter FORMAT = new DateTimeFormatterBuilder()
.appendPattern("yyyyMMdd")
.parseDefaulting(ChronoField.ERA, 1 /* era is AD */)
.toFormatter()
.withChronology(IsoChronology.INSTANCE)
.withResolverStyle(ResolverStyle.STRICT);