You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何阻止Java 8 DateTimeFormatter自动补全秒字段为0?

如何让Java DateTimeFormatter解析后不自动补全缺失的时间字段?

我想要创建一个格式化器,解析字符串后生成不包含秒字段的TemporalAccessor,这样当用需要秒字段的格式器输出时会直接失败。但实际测试中,缺失的秒字段被自动补成了0,和预期不符。

代码示例

DateTimeFormatter partialDateTimeFormatter = new DateTimeFormatterBuilder()
                        .appendPattern("yyyy-MM-d'T'HH:mm")
                        .toFormatter();
                
DateTimeFormatter fullDateTimeFormatter = new DateTimeFormatterBuilder()
                        .appendPattern("yyyy-MM-d'T'HH:mm:ss.SSS")
                        .toFormatter();
                
TemporalAccessor ta = partialDateTimeFormatter.parse("2020-01-02T06:11");

LOGGER.info("seconds supported: {}",ta.isSupported(ChronoField.SECOND_OF_MINUTE));
LOGGER.info("fullDateTimeFormatter: {}",fullDateTimeFormatter.format(ta));

实际输出

12:44:02.561 [main] INFO MatcherTest - seconds supported: true    
12:39:44.370 [main] INFO MatcherTest - fullDateTimeFormatter: 2020-01-2T06:11:00.000

问题原因

官方文档提到:"若至少提供了一天中的小时数,则会生成LocalTime。这会为分钟、秒和毫秒提供默认值。" 也就是说,默认的解析逻辑会自动生成完整的LocalTime(甚至LocalDateTime)实例,这类实例会为所有缺失的时间字段填充默认值(秒、毫秒默认0),导致后续格式化时能正常输出,不符合我们想要的"缺失字段就失败"的预期。

解决方案

要阻止这种自动补全,需要切换到严格解析模式,并避免解析器生成完整的时间对象,只保留解析到的字段集合:

方法一:使用严格解析器风格

DateTimeFormatter partialDateTimeFormatter = new DateTimeFormatterBuilder()
        .appendPattern("yyyy-MM-d'T'HH:mm")
        .parseStrict() // 开启严格解析,拒绝自动补全
        .toFormatter()
        .withResolverStyle(ResolverStyle.STRICT); // 严格解析模式,不填充默认值

DateTimeFormatter fullDateTimeFormatter = new DateTimeFormatterBuilder()
        .appendPattern("yyyy-MM-d'T'HH:mm:ss.SSS")
        .toFormatter();

TemporalAccessor ta = partialDateTimeFormatter.parse("2020-01-02T06:11");

LOGGER.info("seconds supported: {}", ta.isSupported(ChronoField.SECOND_OF_MINUTE));
// 此行会抛出 DateTimeException,因为 ta 不包含秒字段
LOGGER.info("fullDateTimeFormatter: {}", fullDateTimeFormatter.format(ta));

这种方式下,解析得到的TemporalAccessor仅包含解析到的年、月、日、时、分字段,isSupported(ChronoField.SECOND_OF_MINUTE)会返回false,当用需要秒字段的格式器格式化时,直接抛出java.time.DateTimeException: Unable to extract value: ChronoField.SECOND_OF_MINUTE,符合预期。

方法二:自定义解析器(更灵活)

如果需要更细粒度的控制,可以自定义解析逻辑,手动返回仅包含已解析字段的TemporalAccessor:

DateTimeFormatter partialDateTimeFormatter = new DateTimeFormatterBuilder()
        .appendPattern("yyyy-MM-d'T'HH:mm")
        .toFormatter()
        .withResolver((fields, context, style) -> new TemporalAccessor() {
            @Override
            public boolean isSupported(TemporalField field) {
                return fields.containsKey(field);
            }

            @Override
            public long getLong(TemporalField field) {
                if (!isSupported(field)) {
                    throw new DateTimeException("字段不支持: " + field);
                }
                return fields.get(field);
            }
        });

这种方式完全由你控制哪些字段被支持,确保缺失的字段不会被自动补全,格式化时只要用到未支持的字段就会抛出异常。

内容的提问来源于stack exchange,提问作者The Shoe Shiner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 14:10:30