结尾 0 从 Java11 中 ZonedDateTime 对象的毫秒部分被截断

Ending 0's are getting truncated from millisecond part of ZonedDateTime object in Java11

提问人:Ranjit Meher 提问时间:5/29/2023 更新时间:6/6/2023 访问量:223

问:

我正在将我的 Spring Boot 应用程序升级到 Spring Boot 2.7.8 和 Java 11。升级后,我得到了 ZonedDateTime 对象的不同 rest 响应。

我的请求包含“2023-06-23T18:13:06。630元Z[UTC]“,并且我在响应中返回与 Map 键相同的请求对象。但作为回应,从毫秒部分开始结束 0 被修剪“2023-06-23T18:13:06。63Z[UTC]”。

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

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

之前有人遇到过这个问题吗?

此问题的任何解决方案,由于我用作 ZonedDateTime 的 Map 键,因此我需要保持一致。

spring-boot 杰克逊 java-11 zoneddatetime jsr310

评论


答:

1赞 Soheil Babadi 5/29/2023 #1

这是 Jackson 的一个已知问题,会影响对象的序列化。ZonedDateTime

此问题是由于 Jackson 默认使用 Java 的内置 DateTimeFormatter 来序列化和反序列化日期和时间,因此此格式不会以毫秒为单位保留尾随零。

若要解决此问题,可以将 Jackson 配置为使用自定义日期/时间格式,该格式以毫秒为单位保留尾随零

我尝试了这个,并通过为杰克逊创建一个自定义配置:

@Configuration
public class JacksonConfig {

    @Value("${spring.jackson.date-format}")
    private String dateFormat;

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() {
        return builder -> {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat);
            builder.simpleDateFormat(dateFormat).serializers(new ZonedDateTimeSerializer(formatter));
            builder.deserializers(new ZonedDateTimeDeserializer(formatter));
        };
    }

    public static class ZonedDateTimeSerializer extends StdSerializer<ZonedDateTime> {

        private final DateTimeFormatter formatter;

        public ZonedDateTimeSerializer(DateTimeFormatter formatter) {
            super(ZonedDateTime.class);
            this.formatter = formatter;
        }

        @Override
        public void serialize(ZonedDateTime value, JsonGenerator gen, SerializerProvider provider) throws IOException {
            gen.writeString(formatter.format(value));
        }
    }

    public static class ZonedDateTimeDeserializer extends StdDeserializer<ZonedDateTime> {

        private final DateTimeFormatter formatter;

        public ZonedDateTimeDeserializer(DateTimeFormatter formatter) {
            super(ZonedDateTime.class);
            this.formatter = formatter;
        }

        @Override
        public ZonedDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            String value = p.getValueAsString();
            return ZonedDateTime.parse(value, formatter);
        }
    }
}

P.S :此外,您还可以使用此格式化程序来格式化您的 ZonedDateTime 对象,然后再将它们添加到地图中:

ZonedDateTime zdt = ZonedDateTime.parse("2023-06-23T18:13:06.630Z[UTC]");
String formatted = zdt.format(formatter);

Map<String, String> response = new HashMap<>();
response.put(formatted, zdt.toString());

评论

1赞 Ranjit Meher 5/29/2023
感谢您@Soheil的回答,但这无济于事。我尝试了这个解决方案,仍然遇到同样的问题。
0赞 Ranjit Meher 5/29/2023
当 Jackson 序列化其余 API 响应时,我遇到了这个问题,在序列化尾随 0 之前,一旦从毫秒序列化 0 就会被截断。
0赞 Ranjit Meher 6/6/2023
您能建议您使用了哪个${spring.jackson.date-format}吗?
0赞 Soheil Babadi 6/6/2023
@RanjitMeher 我在答案中添加了 P.S
0赞 Ranjit Meher 6/6/2023
我无法更改 MAP 键数据类型,因为它在其他应用程序中具有依赖关系。直到我的休息控制器返回 Response<T> 线点 MAP 具有预期值。一旦它到达 Spring 库,它的序列化值就会发生变化。