Spring Boot和Jackson的日期时区 [英] Date timezone with Spring boot and Jackson

查看:751
本文介绍了Spring Boot和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 批注:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆