【问题标题】:ZonedDateTime round trip via Jackson produces unequal ZonedDateTime通过杰克逊的 ZonedDateTime 往返产生不相等的 ZonedDateTime
【发布时间】:2017-11-06 10:29:08
【问题描述】:

鉴于以下单元测试:

@Test
public void zonedDateTimeCorrectlyRestoresItself() {

    // construct a new instance of ZonedDateTime
    ZonedDateTime now = ZonedDateTime.now(ZoneId.of("Z"));
    // offset = {ZoneOffset@3820} "Z"
    // zone   = {ZoneOffset@3820} "Z"

    String converted = now.toString();

    // restore an instance of ZonedDateTime from String
    ZonedDateTime restored = ZonedDateTime.parse(converted);
    // offset = {ZoneOffset@3820} "Z"
    // zone   = {ZoneOffset@3820} "Z"

    assertThat(now).isEqualTo(restored); // ALWAYS succeeds
}

@Test
public void jacksonIncorrectlyRestoresZonedDateTime()  {

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.findAndRegisterModules();
    objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);

    // construct a new instance of ZonedDateTime
    ZonedDateTime now = ZonedDateTime.now(ZoneId.of("Z"));
    // offset = {ZoneOffset@3820} "Z"
    // zone   = {ZoneOffset@3820} "Z"


    String converted = objectMapper.writeValueAsString(now);

    // restore an instance of ZonedDateTime from String
    ZonedDateTime restored = objectMapper.readValue(converted, ZonedDateTime.class);
    // offset = {ZoneOffset@3820} "Z"
    // zone   = {ZoneOffset@3821} "UTC"

    assertThat(now).isEqualTo(restored); // NEVER succeeds
}

这个解决方法:

@Test
public void usingDifferentComparisonStrategySucceeds() throws Exception  {

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.findAndRegisterModules();
    objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);

    // construct a new instance of ZonedDateTime
    ZonedDateTime now = ZonedDateTime.now(ZoneId.of("Z"));
    // offset = {ZoneOffset@3820} "Z"
    // zone   = {ZoneOffset@3820} "Z"

    String converted = objectMapper.writeValueAsString(now);

    // restore an instance of ZonedDateTime from String
    ZonedDateTime restored = objectMapper.readValue(converted, ZonedDateTime.class);
    // offset = {ZoneOffset@3820} "Z"
    // zone   = {ZoneOffset@3821} "UTC"

    // the comparison succeeds when a different comparison strategy is used
    // checks whether the instants in time are equal, not the java objects
    assertThat(now.isEqual(restored)).isTrue(); 
}

我想我想弄清楚为什么杰克逊内部不打电话给ZonedDateTime.parse()?我个人认为这是杰克逊的一个错误,但我没有足够的信心在没有一些反馈的情况下为它打开一个问题。

【问题讨论】:

    标签: java java-8 jackson zoneddatetime


    【解决方案1】:

    引用维基百科ISO 8601

    如果时间为 UTC,请在时间后直接添加 Z,不带空格。 Z 是零 UTC 偏移的区域指示符。 "09:30 UTC" 因此表示为 "09:30Z""0930Z""14:45:15 UTC" 将是 "14:45:15Z""144515Z"

    UTC 时间也称为祖鲁时间,因为祖鲁是 Z 的北约拼音字母词。

    Z 不是区域。 UTC 是区域,然后在格式化字符串中使用Z表示

    永远不要使用ZoneId.of("Z")。错了。

    【讨论】:

    • ZoneId.of("Z") 并没有比the docs 更错误,它应该可以工作:“如果区域 ID 等于 'Z',则结果是 ZoneOffset.UTC。 ”
    • @OleV.V.我最初使用文档来查找“Z”的 ZoneId,这就是我首先使用它的原因。现在我刚刚用“UTC”替换了所有“Z”实例,但没有看到实例化 ZonedDateTime 对象的杰克逊代码,很难说它是否是一个错误。
    • 如果你使用静态ZoneOffset.UTC也会出现这个问题,所以解决方法并不是避免ZoneId.of("Z")那么简单。
    猜你喜欢
    • 2016-04-18
    • 2016-12-03
    • 1970-01-01
    • 2020-02-07
    • 2022-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-06
    相关资源
    最近更新 更多