一、概念
探讨在 Java 中查看一个字符串是否蕴含无效日期的各种办法,包含 Java8 之前与 Java8 之后及 Apache Commons Validator 的解决方案。
二、日期概述
不论是应该还是办法,在接收数据时,咱们都必须在解决之前验证它的有效性。
在输出日期的状况下咱们须要验证上面几点:
- 输出蕴含无效的日期格局,如 MM/DD/YYYY
- 输出的各个局部都在无效范畴内
- 能够解析为日历中的无效日期
咱们能够用正则表达式来实现上述工作,然而正则在解决各种输出格局时很简单且容易出错,并且还会升高性能。
上面探讨各种灵便、稳键、高效的日期验证的办法。
首先咱们编写一个日期验证的接口。
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));
七、总结
本文总结了验证字符串是否蕴含无效日期的几种办法。