Проверка корректности даты java

How to sanity check a date in Java

I find it curious that the most obvious way to create Date objects in Java has been deprecated and appears to have been «substituted» with a not so obvious to use lenient calendar. How do you check that a date, given as a combination of day, month, and year, is a valid date? For instance, 2008-02-31 (as in yyyy-mm-dd) would be an invalid date.

25 Answers 25

Key is df.setLenient(false); . This is more than enough for simple cases. If you are looking for a more robust (I doubt that) and/or alternate libraries like joda-time, then look at the answer by user «tardate»

final static String DATE_FORMAT = "dd-MM-yyyy"; public static boolean isDateValid(String date) < try < DateFormat df = new SimpleDateFormat(DATE_FORMAT); df.setLenient(false); df.parse(date); return true; >catch (ParseException e) < return false; >> 

@ceklock that’s the way it works, no matter if you use setLenient or not: SimpleDateFormat will always parse until the pattern is matched and ignore the rest of the string, thus you get 201 as year.

Читайте также:  Valid identifiers in python

Incorporating exception handling entails a big performance hit, so this is probably a bad design IF you expect malformed input in normal operation (e.g. validating user input). But if the method is used as a double-check against inputs that are supposed to be valid all the time (except for bugs), it is fine.

FYI, the terribly troublesome old date-time classes such as java.util.Date , java.util.Calendar , and java.text.SimpleDateFormat are now legacy, supplanted by the java.time classes built into Java 8 and later. See Tutorial by Oracle.

As shown by @Maglob, the basic approach is to test the conversion from string to date using SimpleDateFormat.parse. That will catch invalid day/month combinations like 2008-02-31.

However, in practice that is rarely enough since SimpleDateFormat.parse is exceedingly liberal. There are two behaviours you might be concerned with:

Invalid characters in the date string Surprisingly, 2008-02-2x will «pass» as a valid date with locale format = «yyyy-MM-dd» for example. Even when isLenient==false.

Years: 2, 3 or 4 digits? You may also want to enforce 4-digit years rather than allowing the default SimpleDateFormat behaviour (which will interpret «12-02-31» differently depending on whether your format was «yyyy-MM-dd» or «yy-MM-dd»)

A Strict Solution with the Standard Library

So a complete string to date test could look like this: a combination of regex match, and then a forced date conversion. The trick with the regex is to make it locale-friendly.

 Date parseDate(String maybeDate, String format, boolean lenient) < Date date = null; // test date string matches format structure using regex // - weed out illegal characters and enforce 4-digit year // - create the regex based on the local format string String reFormat = Pattern.compile("d+|M+").matcher(Matcher.quoteReplacement(format)).replaceAll("\\\\d"); reFormat = Pattern.compile("y+").matcher(reFormat).replaceAll("\\\\d"); if ( Pattern.compile(reFormat).matcher(maybeDate).matches() ) < // date string matches format structure, // - now test it can be converted to a valid date SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateInstance(); sdf.applyPattern(format); sdf.setLenient(lenient); try < date = sdf.parse(maybeDate); >catch (ParseException e) < >> return date; > // used like this: Date date = parseDate( "21/5/2009", "d/M/yyyy", false); 

Note that the regex assumes the format string contains only day, month, year, and separator characters. Aside from that, format can be in any locale format: «d/MM/yy», «yyyy-MM-dd», and so on. The format string for the current locale could be obtained like this:

Locale locale = Locale.getDefault(); SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateInstance(DateFormat.SHORT, locale ); String format = sdf.toPattern(); 

Joda Time — Better Alternative?

I’ve been hearing about joda time recently and thought I’d compare. Two points:

  1. Seems better at being strict about invalid characters in the date string, unlike SimpleDateFormat
  2. Can’t see a way to enforce 4-digit years with it yet (but I guess you could create your own DateTimeFormatter for this purpose)
import org.joda.time.format.*; import org.joda.time.DateTime; org.joda.time.DateTime parseDate(String maybeDate, String format) < org.joda.time.DateTime date = null; try < DateTimeFormatter fmt = DateTimeFormat.forPattern(format); date = fmt.parseDateTime(maybeDate); >catch (Exception e) < >return date; > 

Источник

Java — how to check if String is valid date?

Geo-Baby

1. Overview

In this post we can find code which can validate if String contains valid Date based on defined pattern.

2. With SimpleDateFormat

import java.text.ParseException; import java.text.SimpleDateFormat; public class Example1 < public static void main(String[] args) < System.out.println(checkIfDateIsValid("2019-10-13")); // true System.out.println(checkIfDateIsValid("2019:10:13")); // false >private static boolean checkIfDateIsValid(String date) < SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); // With lenient parsing, the parser may use heuristics to interpret // inputs that do not precisely match this object's format. format.setLenient(false); try < format.parse(date); >catch (ParseException e) < return false; >return true; > >

3. With SimpleDateFormat + different patterns

import java.text.ParseException; import java.text.SimpleDateFormat; public class Example2 < public static void main(String[] args) < System.out.println("# Example 1"); System.out.println(checkIfDateIsValid("yyyy-MM-dd", "2019-10-13")); // true System.out.println(checkIfDateIsValid("yyyy-MM-dd", "2019:10:13")); // false System.out.println("# Example 2"); System.out.println(checkIfDateIsValid("yyyy/MM/dd", "2019/10/13")); // true System.out.println("# Example 3"); System.out.println(checkIfDateIsValid("yyyy:MM:dd", "2019:10:13")); // true System.out.println("# Example 4"); System.out.println(checkIfDateIsValid("MM/dd/yyyy", "10/13/2019")); // true >private static boolean checkIfDateIsValid(String pattern, String date) < SimpleDateFormat format = new SimpleDateFormat(pattern); // With lenient parsing, the parser may use heuristics to interpret // inputs that do not precisely match this object's format. format.setLenient(false); try < format.parse(date); >catch (ParseException e) < return false; >return true; > >
# Example 1 true false # Example 2 true # Example 3 true # Example 4 true

4. LocalDate — Java 8

import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; public class Example3 < public static void main(String[] args) < System.out.println(checkIfDateIsValid("2019-10-13")); // true System.out.println(checkIfDateIsValid("2019:10:13")); // false >private static boolean checkIfDateIsValid(String date) < try < LocalDate.parse(date, DateTimeFormatter.ISO_DATE); >catch (DateTimeParseException e) < return false; >return true; > >

5. LocalDate + DateTimeFormatter build-in patterns

import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; public class Example4 < public static void main(String[] args) < System.out.println("# Example 1"); System.out.println(checkIfDateIsValid( DateTimeFormatter.ISO_DATE, "2019-10-13")); // true System.out.println(checkIfDateIsValid( DateTimeFormatter.ISO_DATE, "2019:10:13")); // false System.out.println("# Example 2"); System.out.println(checkIfDateIsValid( DateTimeFormatter.BASIC_ISO_DATE, "20191013")); // true System.out.println("# Example 3"); System.out.println(checkIfDateIsValid( DateTimeFormatter.ISO_LOCAL_DATE, "2019-10-13")); // true >private static boolean checkIfDateIsValid(DateTimeFormatter formatter, String date) < try < LocalDate.parse(date, formatter); >catch (DateTimeParseException e) < return false; >return true; > >
# Example 1 true false # Example 2 true # Example 3 true

6. LocalDate + DateTimeFormatter different patterns

import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; public class Example5 < public static void main(String[] args) < System.out.println("# Example 1"); System.out.println(checkIfDateIsValid("yyyy-MM-dd", "2019-10-13")); // true System.out.println(checkIfDateIsValid("yyyy-MM-dd", "2019:10:13")); // false System.out.println("# Example 2"); System.out.println(checkIfDateIsValid("yyyy/MM/dd", "2019/10/13")); // true System.out.println("# Example 3"); System.out.println(checkIfDateIsValid("yyyy:MM:dd", "2019:10:13")); // true System.out.println("# Example 4"); System.out.println(checkIfDateIsValid("MM/dd/yyyy", "10/13/2019")); // true >private static boolean checkIfDateIsValid(String pattern, String date) < try < DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); LocalDate.parse(date, formatter); >catch (DateTimeParseException e) < return false; >return true; > >
# Example 1 true false # Example 2 true # Example 3 true # Example 4 true

References

Источник

Проверьте, является ли строка Допустимой датой в Java

В этом уроке мы обсудим различные способы проверки того, содержит ли Строка допустимую дату в Java.

Мы обсудим решения до Java 8, после Java 8 и с использованием валидатора Apache Commons .

2. Обзор Проверки данных

Всякий раз, когда мы получаем данные в любом приложении, нам необходимо убедиться, что они действительны, прежде чем выполнять дальнейшую обработку.

В случае ввода данных нам может потребоваться проверить следующее:

  • Входные данные содержат дату в допустимом формате, например ММ/ДД/ГГГГ
  • Различные части входных данных находятся в допустимом диапазоне
  • Входные данные преобразуются в действительную дату в календаре

Для этого мы можем использовать регулярные выражения. Однако регулярные выражения для обработки различных форматов и языков ввода сложны и подвержены ошибкам. Кроме того, они могут ухудшить производительность.

Мы обсудим различные способы реализации проверки данных гибким, надежным и эффективным способом.

Во-первых, давайте напишем интерфейс для проверки данных:

public interface DateValidator

В следующих разделах мы реализуем этот интерфейс, используя различные подходы.

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; > >

Поскольку Формат Даты и связанные классы не являются потокобезопасными , мы создаем новый экземпляр для каждого вызова метода.

Далее давайте напишем модульный тест для этого класса:

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 , который представляет дату без времени. Этот класс является неизменяемым и потокобезопасным.

Локальная дата предоставляет два статических метода для анализа дат. Оба они используют 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. Это перечисление , имеющее три возможных значения:

  • СНИСХОДИТЕЛЬНО – разрешает даты и время снисходительно
  • ИНТЕЛЛЕКТУАЛЬНОЕ – интеллектуальное разрешение дат и времени
  • СТРОГО – строго определяет даты и время

Теперь давайте запишем проверку данных с помощью 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

Проект 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:

 commons-validator commons-validator 1.6 

Далее, давайте использовать класс GenericValidator для проверки дат:

assertTrue(GenericValidator.isDate("2019-02-28", "yyyy-MM-dd", true)); assertFalse(GenericValidator.isDate("2019-02-29", "yyyy-MM-dd", true));

7. Заключение

В этой статье мы рассмотрели различные способы проверки того, содержит ли строка допустимую дату.

Как обычно, полный исходный код можно найти на GitHub .

Читайте ещё по теме:

Источник

Оцените статью