1. Обзор
В этом руководстве мы обсудим различные способы проверки того, содержит ли строка
допустимую дату в Java.
Мы рассмотрим решения до Java 8, после Java 8 и с использованием Apache Commons Validator .
2. Обзор проверки даты
Всякий раз, когда мы получаем данные в каком-либо приложении, нам необходимо убедиться, что они действительны, прежде чем выполнять дальнейшую обработку.
В случае ввода даты нам может потребоваться проверить следующее:
- Входные данные содержат дату в допустимом формате, например, ММ/ДД/ГГГГ.
- Различные части ввода находятся в допустимом диапазоне.
- Ввод преобразуется в допустимую дату в календаре.
Мы можем использовать регулярные выражения , чтобы сделать вышеперечисленное. Однако регулярные выражения для обработки различных входных форматов и языковых стандартов сложны и подвержены ошибкам. Они также могут снизить производительность.
Мы обсудим различные способы гибкой, надежной и эффективной реализации проверки даты.
Во-первых, давайте напишем интерфейс для проверки даты:
public interface DateValidator {
boolean isValid(String dateStr);
}
В следующих разделах мы реализуем этот интерфейс, используя различные подходы.
3. Проверка с использованием DateFormat
Java с самого начала предоставляла средства для форматирования и анализа дат. Этот функционал находится в абстрактном классе DateFormat
и его реализации — SimpleDateFormat
.
Давайте реализуем проверку даты с помощью метода parse класса
DateFormat
:
public class DateValidatorUsingDateFormat implements DateValidator {
private String dateFormat;
public DateValidatorUsingDateFormat(String dateFormat) {
this.dateFormat = dateFormat;
}
@Override
public boolean isValid(String dateStr) {
DateFormat sdf = new SimpleDateFormat(this.dateFormat);
sdf.setLenient(false);
try {
sdf.parse(dateStr);
} catch (ParseException e) {
return false;
}
return true;
}
}
Поскольку DateFormat
и связанные с ним классы не являются потокобезопасными `` , мы создаем новый экземпляр для каждого вызова метода.
Далее напишем модульный тест для этого класса:
DateValidator validator = new DateValidatorUsingDateFormat("MM/dd/yyyy");
assertTrue(validator.isValid("02/28/2019"));
assertFalse(validator.isValid("02/30/2019"));
Это было наиболее распространенным решением до Java 8.
4. Подтвердить с помощью LocalDate
В Java 8 представлен улучшенный API даты и времени . Он добавил класс LocalDate
, который представляет дату без времени. Этот класс является неизменяемым и потокобезопасным.
LocalDate
предоставляет два статических метода для анализа дат, и оба используют DateTimeFormatter
для фактического анализа:
public static LocalDate parse(CharSequence text)
// parses dates using using DateTimeFormatter.ISO_LOCAL_DATE
public static LocalDate parse(CharSequence text, DateTimeFormatter formatter)
// parses dates using the provided formatter
Давайте используем метод parse
для реализации проверки даты:
public class DateValidatorUsingLocalDate implements DateValidator {
private DateTimeFormatter dateFormatter;
public DateValidatorUsingLocalDate(DateTimeFormatter dateFormatter) {
this.dateFormatter = dateFormatter;
}
@Override
public boolean isValid(String dateStr) {
try {
LocalDate.parse(dateStr, this.dateFormatter);
} catch (DateTimeParseException e) {
return false;
}
return true;
}
}
Реализация использует объект DateTimeFormatter
для форматирования. Поскольку этот класс потокобезопасен, мы используем один и тот же экземпляр для разных вызовов методов.
Давайте также добавим модульный тест для этой реализации:
DateTimeFormatter dateFormatter = DateTimeFormatter.BASIC_ISO_DATE;
DateValidator validator = new DateValidatorUsingLocalDate(dateFormatter);
assertTrue(validator.isValid("20190228"));
assertFalse(validator.isValid("20190230"));
5. Проверка с помощью DateTimeFormatter
В предыдущем разделе мы видели, что LocalDate
использует объект DateTimeFormatter
для синтаксического анализа. Мы также можем использовать класс DateTimeFormatter
непосредственно для форматирования и синтаксического анализа.
DateTimeFormatter
анализирует текст в два этапа. На этапе 1 он разбирает текст на различные поля даты и времени в зависимости от конфигурации. На этапе 2 он преобразует проанализированные поля в объект даты и/или времени.
Атрибут ResolverStyle
управляет фазой 2. Это перечисление
с тремя возможными значениями:
- LENIENT – снисходительно разрешает дату и время
- SMART – интеллектуально определяет дату и время
- STRICT – разрешает даты и время строго
Теперь давайте напишем проверку даты, используя DateTimeFormatter
напрямую:
public class DateValidatorUsingDateTimeFormatter implements DateValidator {
private DateTimeFormatter dateFormatter;
public DateValidatorUsingDateTimeFormatter(DateTimeFormatter dateFormatter) {
this.dateFormatter = dateFormatter;
}
@Override
public boolean isValid(String dateStr) {
try {
this.dateFormatter.parse(dateStr);
} catch (DateTimeParseException e) {
return false;
}
return true;
}
}
Далее добавим модульный тест для этого класса:
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd", Locale.US)
.withResolverStyle(ResolverStyle.STRICT);
DateValidator validator = new DateValidatorUsingDateTimeFormatter(dateFormatter);
assertTrue(validator.isValid("2019-02-28"));
assertFalse(validator.isValid("2019-02-30"));
В приведенном выше тесте мы создаем DateTimeFormatter
на основе шаблона и локали. Мы используем строгое разрешение для дат.
6. Проверка с помощью Apache Commons Validator
Проект Apache Commons предоставляет платформу проверки. Он содержит процедуры проверки, такие как дата, время, числа, валюта, IP-адрес, адрес электронной почты и URL-адрес.
В этой статье давайте взглянем на класс GenericValidator
, который предоставляет пару методов для проверки того, содержит ли строка
допустимую дату:
public static boolean isDate(String value, Locale locale)
public static boolean isDate(String value,String datePattern, boolean strict)
Чтобы использовать библиотеку, давайте добавим в наш проект зависимость commons-validator Maven:
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.6</version>
</dependency>
Далее воспользуемся классом GenericValidator
для проверки дат:
assertTrue(GenericValidator.isDate("2019-02-28", "yyyy-MM-dd", true));
assertFalse(GenericValidator.isDate("2019-02-29", "yyyy-MM-dd", true));
7. Заключение
В этой статье мы рассмотрели различные способы проверки того, содержит ли строка
допустимую дату.
Как обычно, полный исходный код можно найти на GitHub .