在Java 11中,ZonedDateTime对象的毫秒部分会截断末尾的0。

huangapple go评论176阅读模式
英文:

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

问题

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

我的请求包含"2023-06-23T18:13:06.630Z[UTC]",而我在响应中将相同的请求对象作为Map键返回。但在响应中,毫秒部分的末尾0被截掉了,变成了"2023-06-23T18:13:06.63Z[UTC]"。

请求:

  1. {
  2. "dateList": [
  3. "2023-06-23T18:13:06.630Z[UTC]"
  4. ]
  5. }

响应:

  1. {
  2. "dateList": {
  3. "2023-06-23T18:13:06.63Z[UTC]": "2023-06-23T11:13:06.630-07:00"
  4. }
  5. }

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

对于这个问题有任何解决方案吗?由于我正在将其用作ZonedDateTime的Map键,所以需要保持一致性。

英文:

I am upgrading my spring boot application to spring boot 2.7.8 and Java 11. I getting different rest response of ZonedDateTime object after upgrade.

My request contain "2023-06-23T18:13:06.630Z[UTC]", and I am returning same request object as a Map key in response. But in response ending 0's from millisecond part getting trimmed "2023-06-23T18:13:06.63Z[UTC]".

  1. Request:
  2. {
  3. "dateList": [
  4. "2023-06-23T18:13:06.630Z[UTC]"
  5. ]
  6. }
  7. Response:
  8. {
  9. "dateList": {
  10. "2023-06-23T18:13:06.63Z[UTC]": "2023-06-23T11:13:06.630-07:00"
  11. }
  12. }

Did someone faced earlier this issue?

Any solution to this issue, As I am using as Map key of ZonedDateTime, I need to keep it consistent.

答案1

得分: 1

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

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

要解决这个问题,你可以配置Jackson使用自定义的日期/时间格式,以保留毫秒部分的尾随零。

我尝试过通过创建一个自定义的Jackson配置来实现这个:

  1. @Configuration
  2. public class JacksonConfig {
  3. @Value("${spring.jackson.date-format}")
  4. private String dateFormat;
  5. @Bean
  6. public Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() {
  7. return builder -> {
  8. DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat);
  9. builder.simpleDateFormat(dateFormat).serializers(new ZonedDateTimeSerializer(formatter));
  10. builder.deserializers(new ZonedDateTimeDeserializer(formatter));
  11. };
  12. }
  13. public static class ZonedDateTimeSerializer extends StdSerializer<ZonedDateTime> {
  14. private final DateTimeFormatter formatter;
  15. public ZonedDateTimeSerializer(DateTimeFormatter formatter) {
  16. super(ZonedDateTime.class);
  17. this.formatter = formatter;
  18. }
  19. @Override
  20. public void serialize(ZonedDateTime value, JsonGenerator gen, SerializerProvider provider) throws IOException {
  21. gen.writeString(formatter.format(value));
  22. }
  23. }
  24. public static class ZonedDateTimeDeserializer extends StdDeserializer<ZonedDateTime> {
  25. private final DateTimeFormatter formatter;
  26. public ZonedDateTimeDeserializer(DateTimeFormatter formatter) {
  27. super(ZonedDateTime.class);
  28. this.formatter = formatter;
  29. }
  30. @Override
  31. public ZonedDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
  32. String value = p.getValueAsString();
  33. return ZonedDateTime.parse(value, formatter);
  34. }
  35. }
  36. }

另外,你也可以使用这个格式化器在将ZonedDateTime对象添加到映射之前格式化它们:

  1. ZonedDateTime zdt = ZonedDateTime.parse("2023-06-23T18:13:06.630Z[UTC]");
  2. String formatted = zdt.format(formatter);
  3. Map<String, String> response = new HashMap<>();
  4. response.put(formatted, zdt.toString());
英文:

This is a known issue with Jackson that affects the serialization of ZonedDateTime objects.

This issue is caused by the fact that Jackson by default uses Java's built-in DateTimeFormatter to serialize and deserialize dates and times, so this format does not preserve trailing zeros in milliseconds.

To fix this issue, you can configure Jackson to use a custom date/time format that preserves trailing zeros in milliseconds

I tried this and by creating a custome config for jackson:

  1. @Configuration
  2. public class JacksonConfig {
  3. @Value(&quot;${spring.jackson.date-format}&quot;)
  4. private String dateFormat;
  5. @Bean
  6. public Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() {
  7. return builder -&gt; {
  8. DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat);
  9. builder.simpleDateFormat(dateFormat).serializers(new ZonedDateTimeSerializer(formatter));
  10. builder.deserializers(new ZonedDateTimeDeserializer(formatter));
  11. };
  12. }
  13. public static class ZonedDateTimeSerializer extends StdSerializer&lt;ZonedDateTime&gt; {
  14. private final DateTimeFormatter formatter;
  15. public ZonedDateTimeSerializer(DateTimeFormatter formatter) {
  16. super(ZonedDateTime.class);
  17. this.formatter = formatter;
  18. }
  19. @Override
  20. public void serialize(ZonedDateTime value, JsonGenerator gen, SerializerProvider provider) throws IOException {
  21. gen.writeString(formatter.format(value));
  22. }
  23. }
  24. public static class ZonedDateTimeDeserializer extends StdDeserializer&lt;ZonedDateTime&gt; {
  25. private final DateTimeFormatter formatter;
  26. public ZonedDateTimeDeserializer(DateTimeFormatter formatter) {
  27. super(ZonedDateTime.class);
  28. this.formatter = formatter;
  29. }
  30. @Override
  31. public ZonedDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
  32. String value = p.getValueAsString();
  33. return ZonedDateTime.parse(value, formatter);
  34. }
  35. }
  36. }

P.S :Also you can use this formatter to format your ZonedDateTime objects before adding them to the map:

  1. ZonedDateTime zdt = ZonedDateTime.parse(&quot;2023-06-23T18:13:06.630Z[UTC]&quot;);
  2. String formatted = zdt.format(formatter);
  3. Map&lt;String, String&gt; response = new HashMap&lt;&gt;();
  4. response.put(formatted, zdt.toString());

huangapple
  • 本文由 发表于 2023年5月29日 12:35:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76354701.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定