【问题标题】:Why does Jackson's default deserializer set the Zone to UTC rather than Z?为什么 Jackson 的默认解串器将 Zone 设置为 UTC 而不是 Z?
【发布时间】:2018-05-08 18:18:49
【问题描述】:

我想我一定是误解了 Zones 在 java 的 ZonedDateTime 类中的工作方式。当我使用 Jackson 序列化然后反序列化 now() 时,反序列化的值具有 getZone() == "UTC" 而不是序列化值中的 "Z"。谁能向我解释为什么会这样以及我应该怎么做?

下面的代码打印出来:

{"t":"2017-11-24T18:00:08.425Z"}
Data [t=2017-11-24T18:00:08.425Z]
Data [t=2017-11-24T18:00:08.425Z[UTC]]
Z
UTC

java源码:

<!-- language: java -->

package model;

import static org.junit.Assert.*;

import java.io.IOException;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;

import org.junit.Test;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

public class ZonedDateTimeSerializationTest {

    static public class Data {
        @Override
        public String toString() {
            return "Data [t=" + t + "]";
        }

        public ZonedDateTime getT() {
            return t;
        }

        public void setT(ZonedDateTime t) {
            this.t = t;
        }

        ZonedDateTime t = ZonedDateTime.now(ZoneOffset.UTC);
    };

    @Test
    public void testDeSer() throws IOException {
        Data d = new Data();
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.findAndRegisterModules();
        String serialized = objectMapper.writer()
                .without(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .writeValueAsString(d);
        System.out.println(serialized);

        Data d2 = objectMapper.readValue(serialized, Data.class);
        System.out.println(d);
        System.out.println(d2);
        System.out.println(d.getT().getZone());
        System.out.println(d2.getT().getZone());

        // this fails
        assertEquals(d, d2);
    }
}

【问题讨论】:

  • 我相信Z来自ZoneOffset.UTC,而UTC来自ZoneId.of("UTC")ZoneOffsetZoneId的子类,所以ZoneOffset可以用作ZoneId)。并不是说这回答了你的问题……
  • 而你问的原因是好奇心(我分享),还是其他原因?
  • Ole V.V. - 对于一些预期 ISO8601 日期时间的简单 Web 服务调用,我的单元测试失败了,我不明白为什么。
  • 哦 - 我在我的模型对象中使用 IDE 生成的 equals(),它使用 equals() 而不是 isEqual()。

标签: java json jackson zoneddatetime


【解决方案1】:

默认情况下,在反序列化 ZonedDateTime 期间,Jackson 会将解析的时区调整为上下文提供的时区。您可以使用此设置修改此行为,以便解析的 ZonedDateTime 将保留在 Z

objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);

更多详情here

【讨论】:

  • 谢谢! “上下文提供”,是指 JVM 的时区设置和/或类似的东西吗?如果“根据上下文提供”,反序列化是否也可以将ZonedDateTime 移动到不同的时区?只是好奇。
  • 第二。谢谢
  • @OleV.V. “上下文提供”是指DeserializationContext#getTimeZone() 返回的内容。时区默认为 UTC 而不是 JVM 默认值。可以通过ObjectMapper#setTimeZone()修改。
【解决方案2】:

我这样做是为了实际保留时区:

mapper.enable(SerializationFeature.WRITE_DATES_WITH_ZONE_ID)
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-08
    • 1970-01-01
    • 1970-01-01
    • 2014-03-10
    • 1970-01-01
    • 1970-01-01
    • 2019-01-06
    • 2020-02-21
    相关资源
    最近更新 更多