使用 ObjectMapper 为 JodaTime 设置时区偏移的 Jackson DateTime 格式
Posted
技术标签:
【中文标题】使用 ObjectMapper 为 JodaTime 设置时区偏移的 Jackson DateTime 格式【英文标题】:Jackson DateTime formatting for JodaTime with timezone offset using ObjectMapper 【发布时间】:2021-04-19 10:29:42 【问题描述】:我正在升级 Jackson 库的版本,但遇到了格式化/解析带有时区偏移的 Joda DateTime 的问题。我已经分享了与两个不同版本的 Jackson 库一起使用的示例代码。请让我知道我做错了什么或错过了什么。
jackson-datatype-joda:2.2.4
//jackson-datatype-joda: 2.2.4
@Test
public void jodaDateTimeZoneTest() throws JsonProcessingException
ObjectMapper mapper = getObjectMapper();
DateTime dateTimeInChicago = new DateTime(DateTimeZone.forID("America/Chicago"));
DateTime dateTimeInBucharest = new DateTime(DateTimeZone.forID("Europe/Bucharest"));
System.out.println("the Input Value for Chicago is "+dateTimeInChicago); //Sample input is 2021-01-14T05:32:11.194-06:00
System.out.println("the Input Value for Bucharest is "+dateTimeInBucharest); //Sample input is 2021-01-14T13:32:11.232+02:00
Foo fooChicago = new Foo();
fooChicago.setDateTime(dateTimeInChicago);
System.out.println("the output value for Chicago is "+mapper.writeValueAsString(fooChicago)); //sample ouput is "dateTime":"2021-01-14T05:32:11.194-06:00"
Foo fooBucharest = new Foo();
fooBucharest.setDateTime(dateTimeInBucharest);
System.out.println("the Input Value for Bucharest is "+mapper.writeValueAsString(fooBucharest)); //Sample output is "dateTime":"2021-01-14T13:32:11.232+02:00"
jackson-datatype-joda:2.11.1
//jackson-datatype-joda: 2.11.1
@Test
public void jodaDateTimeZoneTest() throws JsonProcessingException
ObjectMapper mapper = getObjectMapper();
DateTime dateTimeInChicago = new DateTime(DateTimeZone.forID("America/Chicago"));
DateTime dateTimeInBucharest = new DateTime(DateTimeZone.forID("Europe/Bucharest"));
System.out.println("the Input Value for Chicago is "+dateTimeInChicago); //Sample input is 2021-01-14T05:34:27.966-06:00
System.out.println("the Input Value for Bucharest is "+dateTimeInBucharest); //Sample input is 2021-01-14T13:34:28.012+02:00
Foo fooChicago = new Foo();
fooChicago.setDateTime(dateTimeInChicago);
System.out.println("the output value for Chicago is "+mapper.writeValueAsString(fooChicago)); //sample ouput is "dateTime":"2021-01-14T11:34:27.966Z"
Foo fooBucharest = new Foo();
fooBucharest.setDateTime(dateTimeInBucharest);
System.out.println("the Input Value for Bucharest is "+mapper.writeValueAsString(fooBucharest)); //Sample output is "dateTime":"2021-01-14T11:34:28.012Z"
两者的通用代码:
private ObjectMapper getObjectMapper()
ObjectMapper mapper = new ObjectMapper();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
mapper.setDateFormat(dateFormat);
mapper.registerModule(new JodaModule());
return mapper;
public class Foo
private DateTime dateTime;
public DateTime getDateTime()
return dateTime;
public void setDateTime(DateTime dateTime)
this.dateTime = dateTime;
-
使用 2.2.4 将对象转换为字符串后的值
杰克逊是 2021-01-14T05:32:11.194-06:00
在 2.11.1 中,使用将对象转换为字符串后的值
杰克逊是 2021-01-14T11:34:27.966Z
在更高版本中,偏移量被添加/减去
实际时间。
预期: 使用更高版本的 Jackson 库时,如何获得与偏移量相同的值(如 -06:00)?
【问题讨论】:
【参考方案1】:JodaTime DateTimeSerializer
的实现在 2.2 和 2.11 之间发生了很大变化,这是 2.6 发生的最后一次重大变化。
2.6 版引入了一个SerializationFeature.WRITE_DATES_WITH_ZONE_ID
标志来指示被序列化的DateTime
是否应该在其自己的时区和时区 ID 中打印(启用该功能时)或打印为相应的 UTC 时间戳(当该功能已禁用,默认行为)。但是,效果是打印时区偏移量和时区 ID。如果您将 2.11 代码更改为
mapper.enable(SerializationFeature.WRITE_DATES_WITH_ZONE_ID);
mapper.registerModule(new JodaModule());
你会发现输出是
"dateTime":"2021-02-03T08:58:30.632-06:00[America/Chicago]"
使用映射器注册模块时,默认DateTimeSerializer
注册在JodaModule
中。当我尝试注册 DateTimeSerializer
的自定义实例而不是默认实例时,我还没有找到覆盖时区格式的方法(以便只打印偏移量)。
但是,您可以实现并注册您自己的序列化程序,它将完全按照您的需要格式化 DateTime
。基于DateTimeSerializer
逻辑的简单示例:
public class CustomDateTimeSerializer extends JsonSerializer<DateTime>
@Override
public void serialize(DateTime value, JsonGenerator gen, SerializerProvider provider) throws IOException
gen.writeString(FormatConfig.DEFAULT_DATETIME_PRINTER.createFormatter(provider).withOffsetParsed().print(value));
然后配置你的 ObjectMapper:
private ObjectMapper getObjectMapper()
ObjectMapper mapper = new ObjectMapper();
// Instead of .setDateFormat() - see note below
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// Use all the defaults of JodaModule
mapper.registerModule(new JodaModule());
// Override with your custom logic
SimpleModule customJodaModule = new SimpleModule();
customJodaModule.addSerializer(DateTime.class, new CustomDateTimeSerializer());
mapper.registerModule(customJodaModule);
return mapper;
注意:配置
mapper.setDateFormat(dateFormat);
并不会真正影响 JodaTime 日期序列化的格式,但作为副作用,它会禁用 SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
功能。您可以删除 mapper.setDateFormat(dateFormat)
并改为使用
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
注意 2: UTC-06:00 和 [America/Chicago] 不是同义词 - 芝加哥(以及世界上许多其他地方)在夏季观察夏令时,当它移动到 UTC-05:00 时。您必须考虑哪种格式最适合您的目的。为了实现系统之间的最佳互操作性,最好在 UTC 时区发送时间戳(Jackson Joda 模块默认的行为方式)。
注意 3:
您可能需要为 DateTime
配置自定义反序列化器,并为其他 Joda 数据类型配置自定义反序列化器对,只要预期会出现仅打印时区偏移的相同行为。
【讨论】:
我认为这是正确的答案。 mapper.registerModule(new JodaModule()); mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);,并且必须在我的 Pojo 中的 DateTime 属性上指定 @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd@HH:mm:ss.SSSZ")以上是关于使用 ObjectMapper 为 JodaTime 设置时区偏移的 Jackson DateTime 格式的主要内容,如果未能解决你的问题,请参考以下文章
使用 ObjectMapper - 如何将 JSON 结果快速转换为 TableView
使用 ObjectMapper 为 JodaTime 设置时区偏移的 Jackson DateTime 格式
swift 使用ObjectMapper将数组转换为Realm的List类型