如何构建带开头可选小时段的DateTimeFormatter以正常解析时间码
结论验证
你的推测完全正确。DateTimeFormatter的appendOptional采用贪婪匹配策略,解析20:33.123时,开头的20:刚好匹配你定义的UNLIMITED_HOURS规则(两位数字+冒号),会被直接识别为小时段,剩余待解析内容变为33.123,无法匹配后续要求的「两位分钟+冒号」规则,因此抛出索引5位置的解析异常。
此外你原有代码还存在一个隐藏问题:parseDefaulting配置在可选的UNLIMITED_HOURS构造器中,只有当小时段被成功匹配时默认值才会生效,省略小时的场景下默认值不会被注入。
解决方案
推荐采用双可选分支的写法,优先匹配更长的带小时格式,再匹配不带小时的格式,同时调整小时的宽度配置以支持大于24的多位数小时:
DateTimeFormatter TIMECODE = new DateTimeFormatterBuilder() // 分支1:优先匹配带小时的完整格式,支持最多10位小时(可按需调整上限) .appendOptional(new DateTimeFormatterBuilder() .appendValue(ChronoField.HOUR_OF_DAY, 2, 10, SignStyle.NEVER) .appendLiteral(':') .appendValue(MINUTE_OF_HOUR, 2) .appendLiteral(':') .appendValue(SECOND_OF_MINUTE, 2) .appendFraction(MILLI_OF_SECOND, 3, 3, true) .toFormatter(Locale.ENGLISH)) // 分支2:匹配不带小时的格式,默认小时为0 .appendOptional(new DateTimeFormatterBuilder() .parseDefaulting(ChronoField.HOUR_OF_DAY, 0) .appendValue(MINUTE_OF_HOUR, 2) .appendLiteral(':') .appendValue(SECOND_OF_MINUTE, 2) .appendFraction(MILLI_OF_SECOND, 3, 3, true) .toFormatter(Locale.ENGLISH)) .toFormatter(Locale.ENGLISH);
如果使用自定义TimecodeHour字段,只需把代码中的ChronoField.HOUR_OF_DAY替换为TimecodeHour.HOUR即可。
内容的提问来源于stack exchange,提问作者Tobias Wohlfarth
相关产品推荐
相关产品推荐

