此问题是针对杰克逊使用Joda-Time对 DateTime jackson-datatype-joda module 进行反序列化。是否有一个默认时区,日期字符串将被反序列化?如果是这样,它是什么?是 UTC 吗?
我需要问这个,因为杰克逊的文档并不是专门针对Joda-Time DateTime的。我在本文(http://wiki.fasterxml.com/JacksonFAQDateHandling)中发现,杰克逊将 GMT 作为反序列化为java.util.Date
或java.util.Calendar
的默认时区。但是,本文档中没有提及Joda-Time数据类型。另外,我特别需要字符串使用 UTC 时区反序列化为DateTime
个对象,而不是GMT:尽管这两个区域非常相似,但是存在一些小差异,因此GMT不会对我来说是可行的。
谢谢。
答案 0 :(得分:22)
DateTimeDeserializer
的源代码显示它使用DeserializationContext
的时区,该时区由反序列化期间的ObjectMapper
提供。如果您查看ObjectMapper
API,您会看到有设置时区的方法:
public ObjectMapper setTimeZone(TimeZone tz)
因此,您可以使用此方法配置ObjectMapper
并将时区设置为正确的时区。
对于默认值的问题,似乎Javadoc说了一件事,但代码显示了另一件事。
ObjectMapper.setTimeZone(TimeZone tz)
的Javadoc:
/**
* 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)
上设置。
答案 1 :(得分:17)
对于商业应用,UTC和GMT之间没有实际差异。唯一的区别与亚秒级分辨率和每隔几年增加Leap Second有关。对于科学,天文学,卫星跟踪和此类应用程序而言,差异可能很大,但这种情况很少见。
我不知道 Jackson 。但是从查看你链接的文档来看,它们看起来像是序列化了(a)自1970年1月1日UTC以来的毫秒数,或者(b)字符串格式,默认为ISO 8601格式:“1970 -01-01T00:00:00.000 + 0000" 。因此,为了回答关于时区的问题,听起来默认情况下杰克逊总是使用UTC(没有时区偏移)进行序列化,这是正确的方法。如果您关心当时正在使用的时区,您应该在单独的字段中记录该事实(什么时区)。
这两个序列化值(毫秒和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。你很快就会掌握它。我建议你让Jackson默认做任何想做的事,然后在Joda-Time中操纵。 Joda-Time是针对日期时间的粗糙问题而建立的,而Jackson可能不是。 Joda-Time有两种构造函数和方法可以根据需要在时区之间进行调整。
在Java 8中,JSR 310: Date and Time API将类似Joda-Time的类构建到Java平台中。期待看到像 Jackson 这样的框架更新为直接使用这些新类,同时弃用丑陋的java.util.Date/Calendar类。
看起来jackson-datatype-joda project正试图为Joda-Time带来这种便利。但这对我来说似乎没有必要。您可以在java.util.Date/Calendar和Joda-Time之间进行转换,如上所述。
P.S。该项目文档的“Wiki”链接失败。所以我无法查看他们的文档。
答案 2 :(得分:4)
我也在使用日期格式,最后我找到了解决方案。我想使用格式"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
)。
答案 3 :(得分:1)
从一个简单的代码中我发现,当杰克逊从字符串反序列化为Date对象时,如果没有提到时区,则会给出UTC,但直接实例化后gives default timezone即机器的时区。
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