ZonedDateTime通过杰克逊往返产生不平等的ZonedDateTime

ano*_*932 3 java jackson java-8 zoneddatetime

鉴于以下单元测试:

@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
}
Run Code Online (Sandbox Code Playgroud)

这个解决方法:

@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(); 
}
Run Code Online (Sandbox Code Playgroud)

我想我想弄清楚杰克逊内部为什么不打电话ZonedDateTime.parse()?就我个人而言,我认为这是杰克逊的一个错误,但我没有足够的信心为它提出一个问题,但却没有一些反馈意见.

And*_*eas 6

引用维基百科的ISO 8601:

如果时间是UTC,则在Z没有空格的时间之后直接添加.Z是零UTC偏移的区域指示符."09:30 UTC"因此表示为"09:30Z""0930Z"."14:45:15 UTC"会是"14:45:15Z""144515Z".

UTC时间也称为Zulu时间,因为Zulu是Z的北约语音字母.

Z不是区域.UTC是区,然后将其表示使用Z中的格式化字符串.

不要使用ZoneId.of("Z").这是不对的.

  • `ZoneId.of("Z")`并没有比根据[文档]更错误(https://docs.oracle.com/javase/8/docs/api/java/time/ZoneId.html#of- java.lang.String-)它应该工作:"如果区域ID等于'Z',结果是`ZoneOffset.UTC`." (3认同)