乐趣区

关于java:Java中检查字符串是否是有效日期

一、概念

探讨在 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_DATE

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

七、总结

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

退出移动版