Почему это (не) происходит?
Это не очень хорошо объяснено в документации.
При мягком анализе синтаксический анализатор может использовать эвристикуинтерпретировать входные данные, которые точно не соответствуют формату этого объекта.При строгом разборе входные данные должны соответствовать формату этого объекта.
Документация немного помогает, хотя, упоминая, что это объект Calendar
, который использует DateFormat
, является мягким.Этот объект Calendar
используется не для самого анализа, а для интерпретации проанализированных значений в дату и время (я цитирую документацию DateFormat
, поскольку SimpleDateFormat
является подклассом DateFormat
).
SimpleDateFormat
, независимо от того, снисходительно или нет, примет трехзначный год, например 199
, даже если вы указали yyyy
в строке шаблона формата.Документация говорит о годе:
Для синтаксического анализа, если количество букв шаблона превышает 2, год интерпретируется буквально, независимо от количества цифр.Таким образом, используя шаблон «ММ / ДД / ГГГГ», «01/11/12» анализирует до 11 января 12 года нашей эры.
DateFormat
, независимо от того, снисходительно илинет, принимает и игнорирует текст после проанализированного текста, как маленькая буква o
в вашем первом примере.Он возражает против неожиданного текста до или внутри текста, как, например, когда в последнем примере вы поставили букву o
впереди.Документация DateFormat.parse
гласит:
Метод не может использовать весь текст данной строки.
Как я косвенно сказал,снисходительность имеет значение при интерпретации проанализированных значений в дату и время.Таким образом, снисходительный SimpleDateFormat
будет интерпретировать 29.02.2019 как 01.03.2019, потому что в феврале 2019 года только 28 дней. Строгий SimpleDateFormat
откажется сделать это и выдаст исключение.Мягкое поведение по умолчанию может привести к очень неожиданным и совершенно необъяснимым результатам.В качестве простого примера, приведение дня, месяца и года в неправильном порядке: 1990.03.12
приведет к 11 августа 17 года нашей эры (2001 год назад).
Решение
VGR уже в комментарии упоминает LocalDate
от java.time
, современного Java-API даты и времени.По моему опыту java.time
намного приятнее работать, чем старые классы даты и времени, поэтому давайте попробуем.Сначала попробуйте ввести правильную строку даты:
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd.mm.yyyy");
System.out.println(LocalDate.parse("03.12.1990", dateFormatter));
Получено:
java.time.format.DateTimeParseException: текст '03 .12.1990 'не может быть проанализирован: невозможно получитьLocalDate из TemporalAccessor: {Year = 1990, DayOfMonth = 3, MinuteOfHour = 12}, ISO типа java.time.format.Parsed
Это потому, что я использовал вашу строку шаблона формата dd.mm.yyyy
где строчные буквы mm
означают минуты.Когда мы достаточно внимательно читаем сообщение об ошибке, оно говорит о том, что DateTimeFormatter
интерпретировал 12 как минуту часа, что было не тем, что мы намеревались.Хотя SimpleDateFormat
молчаливо принял это (даже если строго), java.time
более полезно указать на нашу ошибку.В сообщении только косвенно говорится, что в нем отсутствует значение месяца.Нам нужно использовать прописные буквы MM
для месяца.В то же время я пробую вашу строку даты с опечаткой:
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
System.out.println(LocalDate.parse("03.12.199o", dateFormatter));
Мы получаем:
java.time.format.DateTimeParseException: Text '03 .12.199o 'могла быне может быть проанализирован с индексом 6
Индекс 6 - это то, где написано 199
.Он возражает, потому что мы указали 4 цифры и поставляем только 3. Документы говорят:
Количество букв определяет минимальную ширину поля…
Это также будет возражатьчтобы разобрать текст после даты.Короче говоря мне кажется, что он дает вам все, что вы ожидали.
Ссылки