使用Jackson(Joda-Time模块)进行DateTime反序列化的默认时区

这个问题是关于使用jackson的jackson-datatype-joda模块对Joda-Time DateTime进行反序列化。 是否有一个默认时区,日期字符串将被反序列化? 如果是这样,它是什么? 是UTC吗?

我需要问这个,因为jackson的文档并不是特定的Joda-Time DateTime。 我在本文( http://wiki.fasterxml.com/JacksonFAQDateHandling )中发现,Jackson会将GMT作为反序列化为java.util.Datejava.util.Calendar的默认时区。 但是,本文档中没有提及Joda-Time数据类型。 另外,我特别需要使用UTC时区将字符串反序列化为DateTime对象,而不是GMT:尽管这两个区域非常相似,但是存在一些小差异,因此GMT对我来说是不可行的。

谢谢。

DateTimeDeserializer的源代码显示它使用DeserializationContext中的时区,该时区由DeserializationContext期间的ObjectMapper提供。 如果你看一下ObjectMapper API,你会看到有设置时区的方法:

 public ObjectMapper setTimeZone(TimeZone tz) 

因此,您可以使用此方法配置ObjectMapper并将时区设置为正确的时区。

对于默认值的问题,似乎Javadoc说了一件事,但代码显示了另一个。

ObjectMapper.setTimeZone(TimeZone tz) Javadoc ObjectMapper.setTimeZone(TimeZone tz)

 /** * Method for overriding default TimeZone to use for formatting. * Default value used is {@link TimeZone#getDefault()}. */ 

但是,代码明确设置时区:

 protected final static BaseSettings DEFAULT_BASE = new BaseSettings( ... // TimeZone.getDefault() TimeZone.getTimeZone("GMT"), ... 

所以,显然,它实际上使用GMT,而不是默认的JVM默认值。

我想说最好的选择可能不是依靠这个并且自己在ObjectMapper.setTimeZone(TimeZone tz)上设置它。

UTC与GMT

对于商业应用, UTC和GMT之间没有实际差异。 唯一的区别在于亚秒级分辨率和每隔几年增加一次闰秒 。 对于科学,天文学,卫星跟踪和此类应用程序而言,差异可能很大,但这种情况很少见。

jackson默认为UTC / GMT

我不认识jackson 。 但是通过查看您链接的文档,它们看起来像是序列化(a)自1970年1月1日UTC以来的毫秒数,或者(b)字符串格式,默认为ISO 8601格式:“1970-01- 01T00:00:00.000 + 0000″ 。 因此,要回答关于时区的问题,听起来默认情况下jackson总是使用UTC(无时区偏移)进行序列化,这是正确的方法。 如果您关心当时正在使用的时区,则应在单独的字段中记录该事实(在哪个时区)。

jackson↔java.util.Date/Calendar↔Joda-Time

这两个序列化值(毫秒和ISO 8601字符串)都可以与Joda-Time DateTime实例的构造函数一起使用。

 String dateTimeString = "2013-11-22T18:37:55.645+0000"; org.joda.time.DateTime myDateTime = org.joda.time.format.ISODateTimeFormat.dateTime().withZoneUTC().parseDateTime( dateTimeString ); 

和…

 Long millisSinceEpoch = 1385495462L; org.joda.time.DateTime myDateTime = new org.joda.time.DateTime( millisSinceEpoch ); 

如果您无法直接访问这些序列化值以提供给Joda-Time DateTime构造函数,那么让Jackson实例化java.util.Date/Calendar对象。 将这些java.util.Date/Calendar对象提供给Joda-Time以实例化DateTime对象以进行进一步的工作。 Joda-Time用户通常会这样做。

 org.joda.time.DateTime myDateTime = new org.joda.time.DateTime( someJavaUtilDateFromJackson ); 

您可以通过调用toDateTime()方法并传递所需的时区,轻松地将该UTC时间转换为Joda-Time中的其他时区。

 org.joda.time.DateTimeZone kolkataTimeZone = org.joda.time.DateTimeZone.forID( "Asia/Kolkata" ); org.joda.time.DateTime dateTimeInKolkata = myDateTime.toDateTime( kolkataTimeZone ); 

Joda-Time使用toDate方法轻松转换回java.util.Date。 所以你在Joda-Time的大部分工作都要做,然后转换回java.util.Date与Jackson交流。 回到jackson时,我会将我的DateTimes切换回UTC,这只是为了衡量标准。

 myDateTime.toDateTime( org.joda.time.DateTimeZone.UTC ) 

您可以在StackOverflow.com上找到许多上述Joda-Time操作的示例。

去做就对了

我怀疑你做的有点过于担心而且编码不够。 只需尝试一些小实验,将值传入和传出Jackson和Joda-Time。 你很快就会掌握它。 我建议你让Jackson默认做任何想做的事,然后在Joda-Time中操纵。 Joda-Time是针对日期时间的粗糙问题而建立的,而Jackson可能不是。 Joda-Time具有根据需要在时区之间进行调整的构造函数和方法。

更光明的未来

在Java 8中, JSR 310:Date和Time API为Java平台带来了类似Joda-Time的类。 期待看到像Jackson这样的框架更新为直接使用这些新类,同时弃用丑陋的java.util.Date/Calendar类。

看起来jackson-datatype-joda项目正试图为Joda-Time带来这种便利。 但这对我来说似乎没有必要。 您可以在java.util.Date/Calendar和Joda-Time之间进行转换,如上所述。

PS该项目文档的“Wiki”链接失败。 所以我无法查看他们的文档。

我也挣扎着日期格式,最后我找到了解决方案。 我想使用格式"2016-02-08T12:49:22.876Z"因为它是ISO 8601并且它由JavaScript Date对象使用。 我还想总是使用UTC时区。

我发现这可以使用以下代码完成:

 final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX"); dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); final ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setDateFormat(dateFormat); System.out.println(objectMapper.writeValueAsString(new Date())); 

请注意格式字符串中的X字符。 它受Java 7支持,并在ISO 8601中指定时区。如SimpleDateFormat中所述 ,如果时区偏移为0(UTC),则生成Z (而不是+00:00 )。

从一个简单的代码我发现,当jackson从字符串反序列化为Date对象时,如果没有提到时区,则它给出UTC,但是当直接实例化时,则给出默认时区,即机器的时区。

 DateTime date = new DateTime(2013, 1, 2, 0, 0) //gives local timezone 

以下给出了UTC

 ObjectMapper mapper = new ObjectMapper(); DateTime dt = new DateTime(2013, 1, 2, 0, 0); String serialized = mapper.writeValueAsString(dt); DateTime dt1 = mapper.readValue(serialized, DateTime.class); //gives UTC