如何使用DateTimeFormatter兼容解析dMMyyyy/ddMMyyyy格式日期字符串
DateTimeFormatter兼容dMMyyyy/ddMMyyyy格式解析方案
问题根因
使用dMMyyyy模式字符串直接创建DateTimeFormatter解析失败,是因为Java默认的日期解析规则是贪心匹配:解析器会优先为可变长度的模式符(比如代表日的d)匹配尽可能多的字符,导致后续MM、yyyy的字符位数不足,触发解析异常。
之前两位年的dMMyy模式可以正常兼容5/6位输入,是因为yy为固定2位长度,解析时会优先将末尾2位划分为年份,再拆分前面的3~4位为日和月,四位年的场景下默认不会做这种后置固定长度的优先级处理,因此需要手动构造解析器。
解决方案
通过DateTimeFormatterBuilder手动指定各日期字段的长度范围,即可实现7位(dMMyyyy)、8位(ddMMyyyy)输入的兼容解析:
import java.time.format.DateTimeFormatterBuilder; import java.time.format.SignStyle; import java.time.temporal.ChronoField; // 构造兼容两种格式的解析器 DateTimeFormatter flexibleLongDateFormatter = new DateTimeFormatterBuilder() // 日:长度范围1~2位,不允许出现符号 .appendValue(ChronoField.DAY_OF_MONTH, 1, 2, SignStyle.NEVER) // 月:固定2位 .appendValue(ChronoField.MONTH_OF_YEAR, 2) // 年:固定4位 .appendValue(ChronoField.YEAR, 4) .toFormatter();
测试验证代码
@Test public void dateConversionyyyyFixed() { DateTimeFormatter flexibleFormatter = new DateTimeFormatterBuilder() .appendValue(ChronoField.DAY_OF_MONTH, 1, 2, SignStyle.NEVER) .appendValue(ChronoField.MONTH_OF_YEAR, 2) .appendValue(ChronoField.YEAR, 4) .toFormatter(); String eightBitWithLeadingZero = "02032020"; String sevenBitStr = "2032020"; String eightBitStr = "12032020"; // 解析8位带前导零的日期 LocalDate res1 = LocalDate.parse(eightBitWithLeadingZero, flexibleFormatter); assertNotNull(res1); assertEquals(LocalDate.of(2020, 3, 2), res1); // 解析7位日期 LocalDate res2 = LocalDate.parse(sevenBitStr, flexibleFormatter); assertNotNull(res2); assertEquals(res1, res2); // 解析8位无前置零的日期 LocalDate res3 = LocalDate.parse(eightBitStr, flexibleFormatter); assertNotNull(res3); assertEquals(LocalDate.of(2020, 3, 12), res3); }
内容的提问来源于stack exchange,提问作者Morris Birkholz
相关产品推荐
相关产品推荐

