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

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

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

谢谢。


答案 1

DateTimeDeserializer 的源代码显示它使用在反序列化期间提供的时区。如果你看一下ObjectMapper API,你会看到有设置时区的方法:DeserializationContextObjectMapper

public ObjectMapper setTimeZone(TimeZone tz)

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

对于与默认值有关的内容,Javadoc似乎说了一件事,但代码显示了另一件事。

Javadoc for :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)


答案 2

世界标准时间与格林威治标准时间

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

杰克逊默认为 UTC/GMT

我不认识杰克逊。但是从您链接的文档来看,看起来他们序列化了(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进行通信。当回到杰克逊时,我会把我的DateTimes切换回UTC,只是为了更好地衡量。

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

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

只管去做

我怀疑你做得有点太担心了,编码不够。只需尝试一些小实验,将值传入和传出 Jackson 和 Joda-Time。您很快就会掌握窍门。我建议你让杰克逊在默认情况下做任何它想做的事情,然后在Joda-Time中操纵。Joda-Time是为日期时间的棘手问题而构建的,而Jackson可能不是。Joda-Time具有构造函数和方法,可以根据需要在时区之间进行调整。

更光明的未来

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

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

附言:该项目文档的“Wiki”链接失败。所以我不能看他们的文档。