一、概念

探讨在Java中查看一个字符串是否蕴含无效日期的各种办法,包含Java8之前与Java8之后及Apache Commons Validator的解决方案。

二、日期概述

不论是应该还是办法,在接收数据时,咱们都必须在解决之前验证它的有效性。
在输出日期的状况下咱们须要验证上面几点:

  1. 输出蕴含无效的日期格局,如MM/DD/YYYY
  2. 输出的各个局部都在无效范畴内
  3. 能够解析为日历中的无效日期

咱们能够用正则表达式来实现上述工作,然而正则在解决各种输出格局时很简单且容易出错,并且还会升高性能。
上面探讨各种灵便、稳键、高效的日期验证的办法。
首先咱们编写一个日期验证的接口。

public interface DateValidator {   boolean isValid(String dateStr);}

上面就以不同的办法来实现这个接口。

三、应用DateFormat

Java从一开始就提供了格式化和解析日期的工具。这些性能在抽像类DateFormat和它的实现类SimpleDateFormat中。
让咱们应用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相干类是线程不平安,咱们须要为每个办法调用创立一个新的实例。上面咱们就来写单元测试:

public class DateValidatorUsingDateFormatUnitTest {    @Test    public void givenValidator_whenValidDatePassed_ThenTrue() {        DateValidator validator = new DateValidatorUsingDateFormat("MM/dd/yyyy");        assertTrue(validator.isValid("02/28/2019"));    }    @Test    public void givenValidator_whenInvalidDatePassed_ThenFalse() {        DateValidator validator = new DateValidatorUsingDateFormat("MM/dd/yyyy");        assertFalse(validator.isValid("02/30/2019"));    }}

这是Java 8之前的通常的解决方案。

四、应用LocalDate

Java 8引入了改良的日期和工夫API。增加了LocalDate类,只示意日期。这个类是线程平安的。
LocalDate提供了两个表态办法来解析日期,都应用DateTimeFormatter来解析:

public static LocalDate parse(CharSequence text)// parses dates using using DateTimeFormatter.ISO_LOCAL_DATEpublic static LocalDate parse(CharSequence text, DateTimeFormatter formatter)// parses dates using the provided formatter

上面用这个解析办法来实现日期验证

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

上面写单元测试

public class DateValidatorUsingLocalDateUnitTest {    DateTimeFormatter dateFormatter = DateTimeFormatter.BASIC_ISO_DATE;    DateValidator validator = new DateValidatorUsingLocalDate(dateFormatter);    @Test    public void givenValidator_whenValidDatePassed_ThenTrue() {        assertTrue(validator.isValid("20190228"));    }    @Test    public void givenValidator_whenInValidDatePassed_ThenFalse() {        assertFalse(validator.isValid("20190230"));    }}

五、应用DateTimeFormater

上一节中LocalDate应用DateTimeFormatter对象进行解析,咱们也能够间接应用DateTimeFormatter类进行格式化解析。
DateTimeFormatter分两个阶段解析文本。阶段1,它依据配置将日期字符串解析为日期和工夫字段。阶段2,它将这些日期和工夫字段解析为对象。ResolverStyle管制阶段2,它有3个值:

// 论断// ResolverStyle  formatter.parse(text)      LocalDate.parse(text, formatter)// -------------  ---------------------      ---------------------------------// STRICT         6.31,6.32不合理输入              6.31,6.32抛异样// SMART          6.31按6.30算 6.32抛异样          同左// LENIENT        往后延6.31按7.1算 6.32按7.2算     同左// DateTimeFormatter.ofPatter("yyyy-MM-dd")   是ResolverStyle.SMART模式

上面是间接应用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;    }}

写测试

public class DateValidatorUsingDateTimeFormatterUnitTest {    @Test    public void givenValidator_whenValidDatePassed_ThenTrue() {        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd", Locale.SIMPLIFIED_CHINESE)                .withResolverStyle(ResolverStyle.STRICT);        DateValidator validator = new DateValidatorUsingDateTimeFormatter(dateFormatter);        assertTrue(validator.isValid("2019-02-28"));    }    @Test    public void givenValidator_whenInValidDatePassed_ThenFalse() {        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd", Locale.SIMPLIFIED_CHINESE)                .withResolverStyle(ResolverStyle.STRICT);        DateValidator validator = new DateValidatorUsingDateTimeFormatter(dateFormatter);        assertFalse(validator.isValid("2019-02-30"));    }}

六、应用Apache Commons Validator

Apache Commons我的项目提供了一个验证框架,能够验证日期、工夫、数字、货币、IP、Email和URL。
本文次要看GenericValidator类,它提供了几种办法来验证String是否蕴含无效日期:

public static boolean isDate(String value, Locale locale)  public static boolean isDate(String value,String datePattern, boolean strict)

要应用这个库先增加依赖

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

七、总结

本文总结了验证字符串是否蕴含无效日期的几种办法。