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

Java 11中ZonedDateTime毫秒部分末尾0被截断问题求助

问题解决方案:Spring Boot 2.7.8 + Java 11 下 ZonedDateTime 作为 Map 键序列化时毫秒末尾 0 被截断

问题原因

Spring Boot 默认使用 Jackson 处理 JSON 序列化/反序列化,Jackson 对 ZonedDateTime 的默认序列化逻辑会根据时间的实际精度自动省略末尾的零毫秒(比如将 630 简化为 63)。当 ZonedDateTime 作为 Map 的键时,这种自动简化会导致响应格式与请求格式不一致。

解决方案

通过自定义 Jackson 的键序列化器和反序列化器,强制指定固定的日期时间格式,确保毫秒部分始终保留三位数字。

1. 自定义 ZonedDateTime 键序列化器

创建序列化器类,将 ZonedDateTime 格式化为包含三位毫秒的字符串:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdKeySerializer;
import java.io.IOException;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

public class ZonedDateTimeKeySerializer extends StdKeySerializer {
    // 匹配请求中的格式:保留三位毫秒,带时区标识
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX['['VV']']");

    @Override
    public void serialize(Object key, JsonGenerator gen, SerializerProvider provider) throws IOException {
        if (key instanceof ZonedDateTime) {
            gen.writeFieldName(FORMATTER.format((ZonedDateTime) key));
        } else {
            super.serialize(key, gen, provider);
        }
    }
}

2. 自定义 ZonedDateTime 键反序列化器

确保请求中的日期字符串能被正确解析为带三位毫秒的 ZonedDateTime 对象:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdKeyDeserializer;
import java.io.IOException;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

public class ZonedDateTimeKeyDeserializer extends StdKeyDeserializer {
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX['['VV']']");

    protected ZonedDateTimeKeyDeserializer() {
        super(ZonedDateTime.class);
    }

    @Override
    protected Object _parse(String key, DeserializationContext ctxt) throws IOException {
        return ZonedDateTime.parse(key, FORMATTER);
    }
}

3. 注册自定义序列化/反序列化器到 Spring

创建 Jackson 配置类,将自定义组件注册到 ObjectMapper:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.ZonedDateTime;

@Configuration
public class JacksonConfig {
    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        
        // 注册键序列化器
        module.addKeySerializer(ZonedDateTime.class, new ZonedDateTimeKeySerializer());
        // 注册键反序列化器
        module.addKeyDeserializer(ZonedDateTime.class, new ZonedDateTimeKeyDeserializer());
        
        objectMapper.registerModule(module);
        return objectMapper;
    }
}

验证效果

配置完成后,Map 的键会严格按照 yyyy-MM-dd'T'HH:mm:ss.SSSXXX['['VV']'] 格式序列化,响应中的毫秒部分将保留三位数字,与请求格式完全一致:

{
    "dateList": {
        "2023-06-23T18:13:06.630Z[UTC]": "2023-06-23T11:13:06.630-07:00"
    }
}

内容的提问来源于stack exchange,提问作者Ranjit Meher

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 10:23:32