
Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:
Once the early-adopter seats are all used, the price will go up and stay at $33/year.
Last updated: October 13, 2023
In this tutorial, we’ll discuss the various ways to check if a String contains a valid date in Java.
We’ll look at the solutions before Java 8, after Java 8, and using the Apache Commons Validator.
Whenever we receive data in any application, we need to verify that it’s valid before doing any further processing.
In the case of date inputs, we may need to verify the following:
We can use regular expressions to do the above. However, regular expressions to handle various input formats and locales are complex and error-prone. They can also degrade performance.
We’ll discuss the different ways to implement date validations in a flexible, robust and efficient manner.
First, let’s write an interface for the date validation:
public interface DateValidator {
boolean isValid(String dateStr);
}
In the next sections, we’ll implement this interface using the various approaches.
Java has provided facilities to format and parse dates since the beginning. This functionality is in the DateFormat abstract class and its implementation — SimpleDateFormat.
Let’s implement the date validation using the parse method of the DateFormat class:
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;
}
}
Since the DateFormat and related classes are not thread-safe, we are creating a new instance for each method call.
Next, let’s write the unit test for this class:
DateValidator validator = new DateValidatorUsingDateFormat("MM/dd/yyyy");
assertTrue(validator.isValid("02/28/2019"));
assertFalse(validator.isValid("02/30/2019"));
This was the most common solution before Java 8.
Java 8 introduced an improved Date and Time API. It added the LocalDate class, which represents the date without time. This class is immutable and thread-safe.
LocalDate provides two static methods to parse dates, and both use a DateTimeFormatter to do the actual parsing:
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
Let’s use the parse method to implement the date validation:
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;
}
}
The implementation uses a DateTimeFormatter object for formatting. Since this class is thread-safe, we’re using the same instance across different method calls.
Let’s also add a unit test for this implementation:
DateTimeFormatter dateFormatter = DateTimeFormatter.BASIC_ISO_DATE;
DateValidator validator = new DateValidatorUsingLocalDate(dateFormatter);
assertTrue(validator.isValid("20190228"));
assertFalse(validator.isValid("20190230"));
In the previous section, we saw that LocalDate uses a DateTimeFormatter object for parsing. We can also use the DateTimeFormatter class directly for formatting and parsing.
DateTimeFormatter parses a text in two phases. In phase 1, it parses the text into various date and time fields based on the configuration. In phase 2, it resolves the parsed fields into a date and/or time object.
The ResolverStyle attribute controls phase 2. It is an enum having three possible values:
Now let’s write the date validation using DateTimeFormatter directly:
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;
}
}
Next, let’s add the unit test for this class:
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"));
In the above test, we’re creating a DateTimeFormatter based on pattern and locale. We are using the strict resolution for dates.
The Apache Commons project provides a validation framework. This contains validation routines, such as date, time, numbers, currency, IP address, email and URL.
For this article, let’s take a look at the GenericValidator class, which provides a couple of methods to check if a String contains a valid date:
public static boolean isDate(String value, Locale locale)
public static boolean isDate(String value,String datePattern, boolean strict)
To use the library, let’s add the commons-validator Maven dependency to our project:
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.6</version>
</dependency>
Next, let’s use the GenericValidator class to validate dates:
assertTrue(GenericValidator.isDate("2019-02-28", "yyyy-MM-dd", true));
assertFalse(GenericValidator.isDate("2019-02-29", "yyyy-MM-dd", true));
In this article, we looked at the various ways to check if a String contains a valid date.