Joda DateTimeFormatter含字面量0的格式解析失败,报输入过短异常
问题分析
你的代码抛出异常的核心原因是:当使用"yyyy0MMdd"格式解析"201800101"时,Joda Time会按以下逻辑拆分输入字符串:
- 前4位
2018→ 年份(正确匹配) - 第5位
0→ 匹配格式中的普通字符0(正确匹配) - 第6-7位
00→ 作为月份(MM要求有效值为01-12,00属于无效月份) - 第8-9位
01→ 日期(未被解析到,因为前面的月份已触发无效校验)
你看到的"too short"异常信息应该是被截断了,完整的异常会明确指出无效的月份值。而你的期望是把"201800101"解析为2018-01-01,说明输入字符串中多了一个多余的0(本该是"20180101"却写成了"201800101"),或者月份部分被错误地添加了前置0(比如001代表1月)。
解决方法
根据你的需求,这里提供三种可行的解决方案:
方案1:精准匹配固定结构的解析器
如果输入字符串的固定结构是4位年份 + 多余的0 + 2位月份 + 2位日期,可以用DateTimeFormatterBuilder来精准匹配这种结构:
import org.joda.time.LocalDate; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatterBuilder; public class DateTest { public static void main(String[] args) { DateTimeFormatter formatter = new DateTimeFormatterBuilder() .appendYear(4, 4) // 匹配4位年份 .appendLiteral('0') // 跳过那个多余的0 .appendMonthOfYear(2) // 匹配两位月份 .appendDayOfMonth(2) // 匹配两位日期 .toFormatter(); LocalDate date = formatter.parseLocalDate("201800101"); System.out.println(date); // 输出:2018-01-01 } }
方案2:支持可变长度的月份解析
如果输入中的月份可能是1-3位(比如001代表1月),可以允许月份字段匹配1到3位数字:
import org.joda.time.LocalDate; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatterBuilder; public class DateTest { public static void main(String[] args) { DateTimeFormatter formatter = new DateTimeFormatterBuilder() .appendYear(4, 4) // 4位年份 .appendMonthOfYear(1, 3) // 允许1-3位的月份(001会被解析为1月) .appendDayOfMonth(2) // 两位日期 .toFormatter(); LocalDate date = formatter.parseLocalDate("201800101"); System.out.println(date); // 输出:2018-01-01 } }
方案3:预处理字符串(简单高效)
如果输入字符串的多余0位置不固定,可以先用正则表达式清理掉多余的0,再用标准格式解析:
import org.joda.time.LocalDate; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; public class DateTest { public static void main(String[] args) { String input = "201800101"; // 把年份后多余的0去掉,保留4位年份+2位月份+2位日期的结构 String cleanedInput = input.replaceAll("(\\d{4})0*(\\d{2})(\\d{2})", "$1$2$3"); DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyyMMdd"); LocalDate date = formatter.parseLocalDate(cleanedInput); System.out.println(date); // 输出:2018-01-01 } }
额外提示
- 如果你确实需要解析
00这类无效月份,可以使用宽松解析模式.withResolverStyle(ResolverStyle.LENIENT),但注意00会被解析为上一年的12月,这可能不符合你的期望。 - 建议使用较新的Joda Time版本(比如2.10+),避免旧版本的解析bug。
内容的提问来源于stack exchange,提问作者PrasadU
相关产品推荐
相关产品推荐

