Spring Boot和Jackson的日期时区 [英] Date timezone with Spring boot and Jackson
问题描述
我正在开发一个处理日期的Spring Boot应用程序。当我提交具有 startDateTime
和 endDateTime
的约会对象时(两者均为类型java.util.Date
)我发送这样的格式:
I'm developing a spring boot application that handles dates. When I submit an Appointment object that has a startDateTime
and an endDateTime
(Both are of type java.util.Date
) I send a format like this:
{
"lastName": "Jhon",
"firstName": "Doe",
"email": "jhon.doe@gmail.com",
"description": "MyDescription",
"startDateTime": "2017-10-09T22:43:07.109+0300",
"endDateTime": "2017-10-09T21:40:07.109+0300",
}
当数据持久存储在数据库中时,时区正确,当我尝试取回数据时,它们似乎但是,当我调试时,它们是正确的,一旦它们被杰克逊序列化,我将得到以下输出作为值:
When data is persisted in database it's with the correct timezone, when I try to retrieve my data back, they seem correct when I'm debugging however, once they are serialized by Jackson I have an output with these as value:
"startDateTime": "2017-10-09T19:43:07.109+0000",
"endDateTime": "2017-10-09T18:40:07.109+0000",
如何配置Jackson来使用存储库中数据随附的时区?
How can I configure Jackson to make usage of timezone that comes with the data from my repository?
------更新---------
------Update---------
我尝试了 OffsetDateTime
,但输出结果很奇怪:
I tried the answer with OffsetDateTime
but the output is quite weird:
"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
2017-10-09T22:43:07.109+0300
推荐答案
A java.util.Date
没有任何时区信息。将 String
反序列化为 Date
后,偏移量 +0300
丢失:日期仅保留时间戳记值,并且它不知道它来自的原始时区。
A java.util.Date
doesn't have any timezone information. Once you deserialize a String
to a Date
, the offset +0300
is lost: the date keeps just the timestamp value, and it can't know what's the original timezone it came from.
如果输出必须始终位于 +03:00
偏移量,您可以使用 com.fasterxml.jackson.annotation.JsonFormat $ c $直接在相应字段中进行设置c>批注:
If the output must always be in +03:00
offset, you can set it directly in the respective fields, using the com.fasterxml.jackson.annotation.JsonFormat
annotation:
@JsonFormat(timezone = "GMT+03:00")
private Date startDateTime;
@JsonFormat(timezone = "GMT+03:00")
private Date endDateTime;
这样,日期字段将始终序列化为 +03:00
偏移:
With this, the date fields will always be serialized to +03:00
offset:
{
"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) 。
If the inputs can be in any other offset (not only +03:00
) and you want to preserve it, the java.util.Date
isn't the ideal type. One alternative is to use Jackson Modules Java 8, if you're using Java >= 8.
对于Java 6和7,存在 ThreeTen Backport 和相应的 Jackson模块-尽管我尚未测试,但代码可能相似,因为ThreeTen Backport包含相同的类和方法,只是包不同-(在Java 8中是 java.time
在ThreeTen Backport中是 org.threeten.bp
)。
For Java 6 and 7, there's the ThreeTen Backport and the corresponding Jackson module - I haven't tested, though, but the code might be similar, as the ThreeTen Backport contains the same classes and methods, only the package is different - (in Java 8 is java.time
and in ThreeTen Backport is org.threeten.bp
).
为了保留日期,时间和偏移量,最好的替代方法是 OffsetDateTime
类。因此,您只需要更改字段类型并为其设置相应的格式即可:
To preserve the date, time and offset, the best alternative is the OffsetDateTime
class. So you just need to change the fields type and set the corresponding format to it:
@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
功能,因此保留了偏移量(默认行为是转换为Jackson上下文的时区,可能与输入中使用的时区不同-通过禁用此功能,则保留偏移量。)
In the object mapper, you must also register the JavaTimeModule
and disable the ADJUST_DATES_TO_CONTEXT_TIME_ZONE
feature, so the offsets are preserved (the default behaviour is to convert to Jackson context's timezone, which might not be the same used in the inputs - by disabling this, the offset is preserved).
您可以使用 JacksonConfigurator
(如在此答案中进行解释)并进行以下配置:
You can use a JacksonConfigurator
(as explained in this answer) and do these configurations:
ObjectMapper om = new ObjectMapper();
om.registerModule(new JavaTimeModule());
om.configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false);
此配置通常就足够了,但是您也可以设置 SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
为 false
,以防万一。
This configuration is usually enough, but you can also set SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
to false
as well, just in case.
如果仍然需要使用 java.util.Date
,则可以使用API进行转换。在Java 8中,有一个新的 Date.from
方法:
If you still need to work with java.util.Date
, you can use the API to convert from/to it. In Java 8, there's the new Date.from
method:
// convert to java.util.Date
public Date getStartAsJavaUtilDate() {
return Date.from(startDateTime.toInstant());
}
在ThreeTen Backport中,有 org.threeten .bp.DateTimeUtils
类:
And in ThreeTen Backport, there's the org.threeten.bp.DateTimeUtils
class:
// convert to java.util.Date
DateTimeUtils.toDate(startDateTime.toInstant());
要将日期
转换回 OffsetDateTime
,但是比较棘手。 Date
对象没有时区信息,因此它不知道原始偏移量。一种替代方法是将原始偏移量保留在单独的变量中:
To convert a Date
back to OffsetDateTime
, though, it's more tricky. The Date
object has no timezone information, so it can't know the original offset. One alternative is to keep the original offset in a separate variable:
// keep the original offset
ZoneOffset startDateOffset = startDateTime.getOffset();
然后,您可以将 Date
转换为即时
,然后将其转换为原始偏移量:
Then, you can convert the Date
to Instant
, and then convert it to the original offset:
// convert java.util.Date to original offset (Java 8)
startDateTime = date.toInstant().atOffset(startDateOffset);
// ThreeTen Backport
startDateTime = DateTimeUtils.toInstant(date).atOffset(startDateOffset);
这篇关于Spring Boot和Jackson的日期时区的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!