杰克逊:使用时区 id 解析 ZonedDateTime

Posted

技术标签:

【中文标题】杰克逊:使用时区 id 解析 ZonedDateTime【英文标题】:Jackson: parse ZonedDateTime with timezone id 【发布时间】:2016-12-03 22:38:19 【问题描述】:

使用 Spring MVC (Spring boot) 我可以从

反序列化 ZonedDateTime
2016-07-26T05:30:47+01:00

但不是来自

2016-07-26T05:30:47+01:00 Europe/Paris

我怎样才能显式添加时区并且仍然能够反序列化它?

【问题讨论】:

术语“欧洲/巴黎”表示一个完整的时区,包括任何转换历史、实际和未来的夏令时规则以及基础时区数据的版本。因此,序列化和反序列化可能需要传输所有这些东西,而不仅仅是字符串“Europe/Paris”。在我看来,全部序列化并不是一个好主意。您是否考虑过只序列化 ZonedDateTime 的瞬间以确保更好的性能? 【参考方案1】:

您可以指定带有可选部分(由[] 分隔)的模式,以指示某些字段是可选的,并使用@JsonFormat 注释将其添加到相应的字段中。

以这个类为例:

public class OptionalTimeZoneTest 

    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssXXX[ VV]")
    private ZonedDateTime date;

    // getter and setter

注意最后一部分([ VV]):[] 中的模式是可选部分,因此解析器会尝试解析它(如果存在)。而模式VV 是区域ID(或时区的名称;有关更多详细信息,请查看javadoc)

这样,两种格式都可以读取:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
// add this to preserve the same offset (don't convert to UTC)
mapper.configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false);

// without timezone
String json = " \"date\": \"2016-07-26T05:30:47+01:00\" ";
OptionalTimeZoneTest value = mapper.readValue(json, OptionalTimeZoneTest.class);
System.out.println(value.getDate()); // 2016-07-26T05:30:47+01:00

// with timezone
json = " \"date\": \"2016-07-26T05:30:47+01:00 Europe/Paris\" ";
value = mapper.readValue(json, OptionalTimeZoneTest.class);
System.out.println(value.getDate()); // 2016-07-26T05:30:47+02:00[Europe/Paris]

输出是:

2016-07-26T05:30:47+01:00 2016-07-26T05:30:47+02:00[欧洲/巴黎]

请注意,在第一种情况下,输出是 2016-07-26T05:30:47+01:00(因为它没有时区,所以应用了 +01:00 偏移量)。

但在第二种情况下,输出是2016-07-26T05:30:47+02:00[Europe/Paris],因为在Europe/Paris 时区,26/07/2016 is summer-time(所以偏移量是+02:00)。而java.time API 的实现方式是在解析这样的String 时,时区优先。


如果您希望将所有 ZonedDateTime 实例转换为 UTC,您可以删除此行:

mapper.configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false);

没有它,日期将转换为UTC,输出将是:

2016-07-26T04:30:47Z[UTC] 2016-07-26T03:30:47Z[UTC]

【讨论】:

以上是关于杰克逊:使用时区 id 解析 ZonedDateTime的主要内容,如果未能解决你的问题,请参考以下文章

如何在 spring-mvc 中跳过杰克逊时区校正?

杰克逊解析错误

用杰克逊解析数组

使用杰克逊解析领域模型

使用杰克逊的 LocalDateTime 解析

杰克逊:反序列化(解析)空Unicode