Java 8 LocalDateTime обрабатывает недопустимую дату
Я хотел проверить дату на стороне клиента, поэтому я написал следующий код. Но вместо получения исключения я получаю правильный объект даты для строки даты 31-го февраля, что явно недействительная дата.
public class Test {
public static void main(String[] args) {
String dateFormat = "HH:mm:ss MM/dd/yyyy";
String dateString = "11:30:59 02/31/2015";
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(dateFormat, Locale.US);
try {
LocalDateTime date = LocalDateTime.parse(dateString, dateTimeFormatter);
System.out.println(date);
} catch (Exception e) {
// Throw invalid date message
}
}
}
Выход: 2015-02-28T11: 30: 59
Кто-нибудь знает, почему LocalDateTime
анализирует эту дату вместо того, чтобы бросать исключение.
Ответы
Ответ 1
Вам просто нужен строгий ResolverStyle
.
Разбор текстовой строки происходит в два этапа. Фаза 1 представляет собой основной синтаксический анализ текста в соответствии с полями, добавленными к строителю. Фаза 2 разрешает проанализированные пары значений поля в дату и/или временные объекты. Этот стиль используется для управления тем, как выполняется этап 2, разрешая.
Пример кода - где withResolverStyle(ResolverStyle.STRICT)
- важное изменение, а также использование uuuu
, а не yyyy
(где uuuu
- "год", а "yyyy" - "год эры", и поэтому неоднозначный):
import java.time.*;
import java.time.format.*;
import java.util.*;
public class Test {
public static void main(String[] args) {
String dateFormat = "HH:mm:ss MM/dd/uuuu";
String dateString = "11:30:59 02/31/2015";
DateTimeFormatter dateTimeFormatter = DateTimeFormatter
.ofPattern(dateFormat, Locale.US)
.withResolverStyle(ResolverStyle.STRICT);
try {
LocalDateTime date = LocalDateTime.parse(dateString, dateTimeFormatter);
System.out.println(date);
} catch (DateTimeParseException e) {
// Throw invalid date message
System.out.println("Exception was thrown");
}
}
}
Ответ 2
Java 8 DateTimeFormatter использует yyyy для обозначения YEAR_OF_ERA, а uuuu означает YEAR. Вам нужно изменить строку шаблона следующим образом:
String dateFormat = "HH:mm:ss MM/dd/uuuu";
По умолчанию для параметра DateTimeFormatter используется стиль распознавателя SMART, но вы хотите, чтобы он использовал стиль распознавателя STRICT. Измените код инициализации dateTimeFormatter следующим образом:
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(dateFormat, Locale.US)
.withResolverStyle(ResolverStyle.STRICT);
Ответ 3
try {
SimpleDateFormat df = new java.text.SimpleDateFormat("HH:mm:ss MM/dd/yyyy");
df.setLenient(false);
System.out.println(df.parse("11:30:59 02/29/2015"));
} catch (java.text.ParseException e) {
System.out.println(e);
}
Я нашел одно решение распознать дату как действительную дату с DateFormat.setLenient(boolean). Если вы попытаетесь проанализировать какую-либо недействительную дату, она выдает исключение синтаксического анализа.
Edit:
Java 8
, но это вызовет исключение, если месяц не находится между 1
и 12
, если день больше, чем 32
. Точно не работает. Но в течение месяца он работает.
try {
TemporalAccessor ta = DateTimeFormatter.ofPattern("HH:mm:ss MM/dd/yyyy").parse("11:30:59 02/32/2015");
} catch (Exception e) {
System.out.println(e);
}
Вывод:
java.time.format.DateTimeParseException: Text '11:30:59 02/32/2015' could not be
parsed: Invalid value for DayOfMonth (valid values 1 - 28/31): 32
Ответ 4
Это не округление. В феврале никогда не было 31 дня, и невозможно использовать проверяющий объект даты/времени для представления дня, который не существует.
В результате он принимает неверный ввод и дает наилучшее приближение к правильной дате (последняя дата февраля того же года).
SimpleDateFormat
наследует от DateFormat
, который имеет на нем метод setLenient(boolean value)
. Я ожидал бы, что если вы вызвали setLenient(true)
до синтаксического анализа, он, вероятно, больше пожаловался бы, как подробно описано в javadocs.
Ответ 5
LocalDateTime.parse будет выдавать ошибку только в том случае, если строка, содержащая строки, содержит недопустимые символы, количество дней, превышающее 31 или месяц, превышающее 12.
Например, если вы изменили свой код как таковой:
String dateString = "11:30:59 0zz2/31/2015";
исключение будет вызвано недействительными символами "zz" в пределах вашей даты. Что касается того, почему это "округление" даты так сказать, что я не знаю.
Источник: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html#parse-java.lang.CharSequence-