Check If a String Is a Valid Date in Java – 在Java中检查一个字符串是否是一个有效的日期

最后修改: 2019年 7月 2日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll discuss the various ways to check if a String contains a valid date in Java.

在本教程中,我们将讨论在Java中检查一个String是否包含有效日期的各种方法。

We’ll look at the solutions before Java 8, after Java 8, and using the Apache Commons Validator.

我们将看看Java 8之前、Java 8之后以及使用Apache Commons Validator的解决方案。

2. Date Validation Overview

2.日期验证概述

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:

在日期输入的情况下,我们可能需要验证以下内容。

  • The input contains the date in a valid format, such as MM/DD/YYYY.
  • The various parts of the input are in a valid range.
  • The input resolves to a valid date in the calendar.

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.

在接下来的章节中,我们将用各种方法实现这个接口。

3. Validate Using DateFormat

3.使用DateFormat进行验证

Java has provided facilities to format and parse dates since the beginning. This functionality is in the DateFormat abstract class and its implementation — SimpleDateFormat.

Java从一开始就提供了格式化和解析日期的设施。这个功能在DateFormat 抽象类及其实现 – SimpleDateFormat

Let’s implement the date validation using the parse method of the DateFormat class:

让我们使用DateFormat类的parse方法实现日期验证。

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.

由于DateFormat和相关的类不是线程安全的,我们正在为每个方法的调用创建一个新的实例。

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之前最常见的解决方案。

4. Validate Using LocalDate

4.使用LocalDate进行验证

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.

Java 8 引入了改进的日期和时间 API。它添加了LocalDate类,该类表示没有时间的日期。这个类是不可变的,并且是线程安全的。

LocalDate provides two static methods to parse dates, and both use a DateTimeFormatter to do the actual parsing:

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

Let’s use the parse method to implement the date validation:

让我们使用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;
    }
}

The implementation uses a DateTimeFormatter object for formatting. Since this class is thread-safe, we’re using the same instance across different method calls.

该实现使用一个DateTimeFormatter对象来进行格式化。由于这个类是线程安全的,我们在不同的方法调用中使用同一个实例。

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

5. Validate Using DateTimeFormatter

5.使用DateTimeFormatter进行验证

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.

在上一节中,我们看到LocalDate使用一个DateTimeFormatter对象进行解析。我们也可以直接使用DateTimeFormatter类来进行格式化和解析。

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.

DateTimeFormatter分两个阶段对文本进行解析。在第一阶段,它根据配置将文本解析为各种日期和时间字段。在第二阶段,它将被解析的字段解析为一个日期和/或时间对象。

The ResolverStyle attribute controls phase 2. It is an enum having three possible values:

ResolverStyle属性控制第二阶段。它是一个enum,有三个可能的值。

  • LENIENT – resolves dates and times leniently
  • SMART – resolves dates and times in an intelligent manner
  • STRICT – resolves dates and times strictly

Now let’s write the date validation using DateTimeFormatter directly:

现在让我们直接使用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;
    }
}

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.

在上面的测试中,我们正在创建一个基于模式和地区的DateTimeFormatter。我们对日期使用严格的分辨率。

6. Validate Using Apache Commons Validator

6.使用Apache Commons验证器进行验证

The Apache Commons project provides a validation framework. This contains validation routines, such as date, time, numbers, currency, IP address, email and URL.

Apache Commons项目提供了一个验证框架。这包含验证程序,如日期、时间、数字、货币、IP地址、电子邮件和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:

对于这篇文章,让我们看看GenericValidator类,它提供了几个方法来检查String是否包含一个有效的日期。

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:

为了使用该库,我们把commons-validator Maven依赖项添加到我们的项目。

<dependency>
    <groupId>commons-validator</groupId>
    <artifactId>commons-validator</artifactId>
    <version>1.6</version>
</dependency>

Next, let’s use the GenericValidator class to validate dates:

接下来,让我们使用GenericValidator类来验证日期。

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

7. Conclusion

7.结语

In this article, we looked at the various ways to check if a String contains a valid date.

在这篇文章中,我们研究了检查String是否包含有效日期的各种方法。

As usual, the full source code can be found over on GitHub.

像往常一样,完整的源代码可以在GitHub上找到超过