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

查看:25
本文介绍了使用 Spring Boot 和 Jackson 的日期时区的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个处理日期的 Spring Boot 应用程序.当我提交一个具有 startDateTimeendDateTime 的 Appointment 对象(两者都是 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",
}

当数据保存在数据库中时,它具有正确的时区,当我尝试取回我的数据时,它们在我调试时似乎是正确的,但是,一旦它们被 Jackson 序列化,我就有一个输出,这些值作为值:

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());

Date 转换回 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转换为Instant,然后再转换为原始偏移量:

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天全站免登陆