背景
校验形如"2019-12-12"这样的字符串日期是否有效 使用joda-time及其版本
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.9.9</version>
</dependency>
代码如下:
public boolean validDateFormat(String dateStr) {
DateTimeFormatter df = DateTimeFormat.forPattern("yyyy-MM-dd");
boolean flag = true;
try {
df.parseDateTime(dateStr);
} catch (Exception e) {
LOGGER.error("validDateFormat error, dateStr={}", dateStr, e);
flag = false;
}
return flag;
}
问题
通过验证2019-12-12、2018-01-24返回期待的true;验证2019-02-34返回期待的false。但是当验证1989-04-16时,并未返回期待的true,而是返回了false。异常日志为:
org.joda.time.IllegalInstantException: Cannot parse "1989-04-16": Illegal instant due to time zone offset transition (Asia/Shanghai)
at org.joda.time.format.DateTimeParserBucket.computeMillis(DateTimeParserBucket.java:471) ~[joda-time-2.9.9.jar:2.9.9]
at org.joda.time.format.DateTimeParserBucket.computeMillis(DateTimeParserBucket.java:411) ~[joda-time-2.9.9.jar:2.9.9]
at org.joda.time.format.DateTimeFormatter.parseDateTime(DateTimeFormatter.java:928) ~[joda-time-2.9.9.jar:2.9.9]
经过验证1900-2500年所有时间之后,发现并不是所有时间都会报错,只有1940-06-03、1941-03-16、1986-05-04、1987-04-12、1988-04-10、1989-04-16、1990-04-15、1991-04-14几个时间会有如上错误抛出。(此处数据参考:胡扬封的joda-time踩坑记)
原因
参考官网文档FAQ:FAQ

解决方案
使用最新版本
<!-- joda-time -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10.5</version>
</dependency>
使用parseLocalDateTime()
public boolean validDateFormat(String dateStr) {
DateTimeFormatter df = DateTimeFormat.forPattern("yyyy-MM-dd");
boolean flag = true;
try {
// 使用parseLocalDateTime
df.parseLocalDateTime(dateStr);
} catch (Exception e) {
LOGGER.error("validDateFormat error, dateStr={}", dateStr, e);
flag = false;
}
return flag;
}
使用时区
public boolean validDateFormat(String dateStr) {
// 使用UTC时区
DateTimeFormatter df = DateTimeFormat.forPattern("yyyy-MM-dd").withZoneUTC();
boolean flag = true;
try {
df.parseLocalDateTime(dateStr);
} catch (Exception e) {
LOGGER.error("validDateFormat error, dateStr={}", dateStr, e);
flag = false;
}
return flag;
}