当前位置: 首页 > 知识库问答 >
问题:

Spring Boot和Jackson的日期时区

殳经略
2023-03-14

我正在开发一个处理日期的spring boot应用程序。当我提交一个具有< code>startDateTime和< code>endDateTime的约会对象(两者都属于< code>java.util.Date类型)时,我会发送如下格式:

{
    "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序列化,我就会有一个输出,其中包含以下值:

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

如何配置Jackson以使用存储库中数据附带的时区?

更新---------

我尝试用< code>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

共有2个答案

石正奇
2023-03-14

如果你在春装上使用swagger,并且你的约会总是被连载。
And序列化功能。写日期作为时间戳

问题:SerializationFeature.WRITE_DATES_AS_TIMESTAMPS值未从 spring 配置文件中读取,需要设置 false 才能在序列化时隐藏长整型值。

@Autowired
private RequestMappingHandlerAdapter handlerAdapter;

@EventListener
public void handleContextRefresh(ContextRefreshedEvent event) {
    handlerAdapter
            .getMessageConverters()
            .stream()
            .forEach(c -> {
                if (c instanceof MappingJackson2HttpMessageConverter) {
                    MappingJackson2HttpMessageConverter jsonMessageConverter = (MappingJackson2HttpMessageConverter) c;
                    ObjectMapper objectMapper = jsonMessageConverter.getObjectMapper();
                    objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
                }
            });
}
岳嘉良
2023-03-14

<code>java.util。日期没有任何时区信息。一旦将String反序列化为Date,偏移量 就会丢失:日期只保留时间戳值,它无法知道它的原始时区。

如果输出必须始终处于 03:00 偏移量,则可以使用 com.fasterxml.jackson.annotation.JsonFormat 注释直接在相应的字段中设置它:

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

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

这样,日期字段将始终序列化为< code> 03:00偏移量:

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

如果输入可以是任何其他偏移量(不仅仅是< code> 03:00),并且您想要保留它,那么< code>java.util.Date不是理想的类型。如果你使用Java,另一种选择是使用Jackson Modules Java 8

对于Java 6和7,有ThreeTen Backport和相应的Jackson模块——虽然我没有测试过,但是代码可能是相似的,因为ThreeTen Backport包含相同的类和方法,只是包不同而已(在Java 8中是< code>java.time,在ThreeTen Backport中是< code>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功能,以便保留偏移量(默认行为是转换为 Jackson 上下文的时区,该时区可能与输入中使用的时区不同 - 通过禁用此功能,偏移量将保留)。

您可以使用JacksonConfigurator(如本答案所述)并执行以下配置:

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

这种配置通常就足够了,但是也可以设置< code>SerializationFeature。为了以防万一,也将_DATES_AS_TIMESTAMPS写入< code>false。

如果您仍然需要使用java.util.Date,您可以使用API从/转换到它。在Java8中,有一个新的Date.from方法:

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

在Three十Backport中,有org.threeten.bp.DateTimeUtils类:

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

但是,要将日期转换回偏移日期时间,这更加棘手。Date 对象没有时区信息,因此它无法知道原始偏移量。一种替代方法是将原始偏移量保留在单独的变量中:

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

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

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

// ThreeTen Backport
startDateTime = DateTimeUtils.toInstant(date).atOffset(startDateOffset);
 类似资料:
  • 让我一起学习一个新的内建对象:日期(Date)。该对象存储日期和时间,并提供了日期/时间的管理方法。 例如,我们可以使用它来存储创建/修改时间,或者用来测量时间,再或者仅用来打印当前时间。 创建 创建一个新的 Date 对象,只需要调用 new Date(),在调用时可以带有下面这些参数之一: new Date() 不带参数 —— 创建一个表示当前日期和时间的 Date 对象: let now =

  • 日期和时间 日期、时间、时间戳的值支持ISO 8601格式,格式还包含了时区: CALL TIMESTAMP '2008-01-01 12:00:00+01:00'; 如果未设置时区,将使用系统中当前的时区。日期和时间信息存储在 H2 数据库文件,不包含时区信息。如果数据库打开使用另一个系统时区,日期和时间将是相同的。这意味着如果你存储的值“2000-01-01 12:00:00”在一个时区,然

  • PHP 中 DateTime 类的作用是在你读、写、比较或者计算日期和时间时提供帮助。除了 DateTime 类之外,PHP 还有很多与日期和时间相关的函数,但 DateTime 类为大多数常规使用提供了优秀的面向对象接口。它还可以处理时区,不过这并不在这篇简短的介绍之内。 在使用 DateTime 之前,通过 createFromFormat() 工厂方法将原始的日期与时间字符串转换为对象或使用

  • 必须 使用 Carbon 来处理日期和时间相关的操作。 Laravel 5.1 中文的 diffForHumans 可以使用 jenssegers/date。 Laravel 5.3 及以上版本的 diffForHumans,只需要在 config/app.php 文件中配置 locale 选项即可 : 'locale' => 'zh-CN',

  • 善意提醒 对于那些还没有注意到的读者,近来项目已经迁移到 github 上,你们可以在这个位置找到代码: https://github.com/miguelgrinberg/microblog。 我已经添加了标签指向每个教程步​​骤,为您提供便利。 时间戳的问题 我们 microblog 应用程序已经忽略很长时间的一个方面就是时间和日期的显示。 到目前为止,我们信任 Python 本身去渲染在我们

  • 我有一个使用百里香叶作为视图层的Spring Boot Web应用程序,我需要显示一些特定时区的日期(CET = UTC 1/UTC 2)。 服务器设置为UTC,所有日期都以UTC格式作为datetime存储在我的数据库中,这很好。 现在我想在我的超文本标记语言页面上显示这个日期,不是UTC格式,而是使用胸膜时序的CET,但它似乎不起作用。 date对象是一个Java Instant。 从 DB