FastDateFormat解析"2018-09-31"得异常结果的原因及解决方法
问题解析与解决方案
我来帮你拆解这个日期解析的问题,以及给出对应的解决办法:
为什么会出现不符合预期的结果?
你的核心问题出在FastDateFormat的默认行为上:
- 宽松解析模式:FastDateFormat默认启用了「宽松模式(Lenient Mode)」,这种模式下解析器不会直接拒绝无效日期,而是自动调整为合法日期。比如9月只有30天,输入的
2018-09-31会被当作「9月30日再加1天」,也就是10月1日。 - 时区差异:你看到的两个输出其实是同一个时刻的不同时区展示:
date.toString()用的是你的本地AEST时区(UTC+10),显示为Mon Oct 01 00:00:00 AEST 2018;而date.toInstant()是UTC标准时间,对应的就是2018-09-30T14:00:00Z(因为UTC+10的0点等于UTC的前一天14点)。
如何让解析仅匹配合法的输入日期?
要让解析器严格校验日期合法性,拒绝无效输入,你需要把FastDateFormat切换为严格模式。FastDateFormat可以通过Builder来构建并关闭宽松模式:
修改后的测试代码
import org.apache.commons.lang3.time.FastDateFormat; import java.text.ParseException; import org.junit.Test; public class DateParseTest { // 用Builder创建严格模式的日期格式化器 private static final FastDateFormat dateOnlyFormat = new FastDateFormat.Builder() .setPattern("yyyy-MM-dd") .setLenient(false) // 关键:关闭宽松解析 .build(); @Test public void getSQLDateWithOnlyDate() { java.util.Date date = null; try { String dateString = "2018-09-31"; date = dateOnlyFormat.parse(dateString); System.out.println("input date : " + dateString); System.out.println("date.toInstant() : " + date.toInstant()); System.out.println("date.toString() : " + date.toString()); } catch (ParseException e) { // 无效日期会触发异常,这里可以捕获并处理 System.err.println("输入的日期无效:" + e.getMessage()); e.printStackTrace(); } } }
运行结果
现在输入2018-09-31时,代码会直接抛出ParseException,拒绝解析无效日期,而不是自动修正:
输入的日期无效:Unparseable date: "2018-09-31" java.text.ParseException: Unparseable date: "2018-09-31" at org.apache.commons.lang3.time.FastDateFormat.parse(FastDateFormat.java:497) ...
额外推荐:使用Java 8+的现代日期API
如果你项目使用的是Java 8及以上版本,非常建议换成原生的java.time API(比如LocalDate和DateTimeFormatter),它的设计更合理,默认就是严格模式,而且专门处理日期/时间的类型更清晰:
import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import org.junit.Test; public class ModernDateParseTest { private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); @Test public void parseStrictDate() { try { String dateString = "2018-09-31"; LocalDate date = LocalDate.parse(dateString, dateFormatter); System.out.println("输入日期有效:" + date); } catch (DateTimeParseException e) { System.err.println("无效日期:" + e.getMessage()); } } }
这个代码同样会抛出异常拒绝无效日期,而且LocalDate是无时区的纯日期类型,能避免时区带来的混淆,更适合你只处理日期的场景。
内容的提问来源于stack exchange,提问作者Valath
相关产品推荐
相关产品推荐

