java - 通过 Jackson 的 ZonedDateTime 往返产生不相等的 ZonedDateTime

标签 java java-8 jackson 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
}

这个解决方法:

@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(); 
}

我想我想弄清楚为什么 Jackson 内部不调用 ZonedDateTime.parse()?我个人认为这是 Jackson 的一个错误,但我还没有足够的信心在没有任何反馈的情况下为它打开一个问题。

最佳答案

引用维基百科 ISO 8601 :

If the time is in UTC, add a Z directly after the time without a space. Z is the zone designator for the zero UTC offset. "09:30 UTC" is therefore represented as "09:30Z" or "0930Z". "14:45:15 UTC" would be "14:45:15Z" or "144515Z".

UTC time is also known as Zulu time, since Zulu is the NATO phonetic alphabet word for Z.

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

永远不要使用 ZoneId.of("Z")。这是错误的。

关于java - 通过 Jackson 的 ZonedDateTime 往返产生不相等的 ZonedDateTime,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44372498/

相关文章:

java - Jackson - 自定义反序列化器不会读取 JSON 中的所有字段

java - 在现有 Java 7 代码中使用 Java 8 Optional

java - 如何使用 Hibernate 将 java.time.LocalDateTime 映射到 H2 数据库中的 TIMESTAMP?

Java优化问题

java - java中的守护线程

java - 并行 flatMap 总是顺序的

java - 没有名称/前缀的 Jackson QName 序列化

java - FasterXML - Jackson XML 扩展将 pojo 中的值转换为 null

java - 在 IText 7 中对所有 PDF 页面使用单一模板

java - 是否有用于使用体素引擎进行渲染的 Java 库?