使用Spring引导和杰克逊日期时区

问题描述:

我正在开发处理日期的弹簧引导应用程序。当我提交具有startDateTimeendDateTime(两者都是java.util.Date类型的)约会对象我送的格式是这样的:使用Spring引导和杰克逊日期时区

{ 
    "lastName": "Jhon", 
    "firstName": "Doe", 
    "email": "[email protected]", 
    "description": "MyDescription", 
    "startDateTime": "2017-10-09T22:43:07.109+0300", 
    "endDateTime": "2017-10-09T21:40:07.109+0300", 
} 

当数据在数据库坚持它与正确的时区,当我尝试找回我的数据传回,他们似乎正确的,当我在调试然而,一旦被杰克逊系列化我有这些的输出值:

"startDateTime": "2017-10-09T19:43:07.109+0000", 
"endDateTime": "2017-10-09T18:40:07.109+0000", 

如何配置杰克逊做出自带的时区的使用我的资料库中的数据?

------更新---------

我想答案与OffsetDateTime但输出是相当奇怪:

"startDateTime": { 
     "offset": { 
      "totalSeconds": 7200, 
      "id": "+02:00", 
      "rules": { 
       "fixedOffset": true, 
       "transitionRules": [], 
       "transitions": [] 
      } 
     }, 
     "month": "OCTOBER", 
     "year": 2017, 
     "hour": 21, 
     "minute": 49, 
     "nano": 654000000, 
     "second": 15, 
     "dayOfMonth": 9, 
     "dayOfWeek": "MONDAY", 
     "dayOfYear": 282, 
     "monthValue": 10 
    } 

我想有什么像:

2017-10-09T22:43:07.109 + 0300

+0

使用DateTime类是更适合这种情况 – CodeIsLife

+0

如果OffsetDateTime字段(如下面的答案中所示),您是否使用了'JsonFormat'注释? – 2017-10-09 19:55:29

+0

是的,我添加了这个注解,但仍然没有工作 – Habchi

java.util.Datedoesn't have any timezone information。将String反序列化为Date后,将会丢失偏移+0300:该日期只保留时间戳值,并且无法知道其来源的原始时区是什么。

如果输出必须始终+03:00偏移,您可以直接在各自领域设置,使用com.fasterxml.jackson.annotation.JsonFormat注释:

@JsonFormat(timezone = "GMT+03:00") 
private Date startDateTime; 

@JsonFormat(timezone = "GMT+03:00") 
private Date endDateTime; 

这样,日期字段将永远被序列化到+03:00偏移:

{ 
    "startDateTime":"2017-10-09T22:43:07.109+0300", 
    "endDateTime":"2017-10-09T21:40:07.109+0300" 
} 

如果输入可以是任何其它偏移量(不仅+03:00)和你想保留它,java.util.Date不是理想的类型。一种选择是使用Jackson Modules Java 8,如果你使用的是Java> = 8

对于Java 6和7,还有的ThreeTen Backport和相应的Jackson module - 我没有测试过,虽然,但代码可能是相似,因为ThreeTen Backport包含相同的类和方法,所以只有软件包不同 - (在Java 8中为java.time,在ThreeTen Backport中为org.threeten.bp

要保存日期,时间和偏移量,最好的选择是OffsetDateTime类。所以,你只需要改变的字段类型,并设置相应的格式它:

@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXX") 
private OffsetDateTime startDateTime; 

@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXX") 
private OffsetDateTime endDateTime; 

在对象映射,你还必须注册JavaTimeModule和禁用ADJUST_DATES_TO_CONTEXT_TIME_ZONE feature,所以偏移被保留(默认行为是转换为Jackson上下文的时区,这可能与输入中使用的时区不同 - 通过禁用此功能,偏移量将保留)。

可以使用JacksonConfigurator(如explained in this answer),做这些配置:

ObjectMapper om = new ObjectMapper(); 
om.registerModule(new JavaTimeModule()); 
om.configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false); 

这种配置通常是不够的,但你也可以设置SerializationFeature.WRITE_DATES_AS_TIMESTAMPSfalse为好,以防万一。


如果您仍然需要java.util.Date工作,你可以使用API​​来/将其转换。在Java 8,有一个新的Date.from方法:

// convert to java.util.Date 
public Date getStartAsJavaUtilDate() { 
    return Date.from(startDateTime.toInstant()); 
} 

而且在ThreeTen反向移植,还有的org.threeten.bp.DateTimeUtils类:

// convert to java.util.Date 
DateTimeUtils.toDate(startDateTime.toInstant()); 

要将Date转换回OffsetDateTime,不过,它更棘手。 Date对象没有时区信息,因此无法知道原始偏移量。一种选择是保留原来在一个单独的可变偏移:

// keep the original offset 
ZoneOffset startDateOffset = startDateTime.getOffset(); 

然后,您可以转换DateInstant,然后将其转换为原始偏移:

// convert java.util.Date to original offset (Java 8) 
startDateTime = date.toInstant().atOffset(startDateOffset); 

// ThreeTen Backport 
startDateTime = DateTimeUtils.toInstant(date).atOffset(startDateOffset); 
+0

spring.jackson.time-zone配置如何?注释适用于我,而春季配置则不适用。 –