Spring REST LocalDate UTC一天不同 [英] Spring REST LocalDate UTC differs of one day

查看:106
本文介绍了Spring REST LocalDate UTC一天不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Spring Boot 1.5.4,Hibernate 5.2.10,Spring Data REST,HATEOAS,带有LocalDate和LocalDateTime的JDK8. 我的计算机处于CEST时区,但是我希望该应用程序可以在UTC上运行,所以我在application.properties中进行了设置:

I'm using Spring Boot 1.5.4, Hibernate 5.2.10, Spring Data REST, HATEOAS, JDK8 with LocalDate and LocalDateTime. My computer is on CEST timezone but I want the application works in UTC, so I set in application.properties:

spring.datasource.url=jdbc:mysql://localhost:3306/database?useLegacyDatetimeCode=false&serverTimezone=UTC&useSSL=true
spring.jpa.hibernate.jdbc.time_zone = UTC

根据此文章我不想更改JVM的时区,因为这似乎不是最佳实践.

According to this article I don't want to change the timezone of my JVM because seems not to be a best practice.

Spring Data REST公开了我的存储库,并且我使用Swagger2有一个不错的接口来使用API​​. 当我尝试端点时,会看到类似以下内容的

Spring Data REST exposes my repositories and I use Swagger2 to have a nice interface to use API. When I try a endpoint I see something like:

    {
  "_embedded": {
    "dailyCodes": [
      {
        "sid": "d495cdaa-14f2-44cb-a98f-8aa6ddd43d91",
        "createdDate": "2017-06-28T16:20:01",
        "lastModifiedDate": "2017-06-28T16:20:01",
        "lastModifiedBy": "admin",
        "date": "2017-06-28",
        "code": "js",
        "new": false,
        "_links": {
          "self": {
            "href": "http://localhost:8080/api/v1/dailyCodes/1"
          },
          "dailyCode": {
            "href": "http://localhost:8080/api/v1/dailyCodes/1"
          }
        }
      }

就像您看到的日期时间格式一样,即使数据库中的实时时间是14:20:01,它也会显示CEST时间. 我猜这是错误的,因为我的REST API应该可以在UTC上运行.

Like you can see the datetime format is fine and also it display the CEST time even if in the db the real time is 14:20:01. I guess this is wrong because my REST API should work in UTC.

我怎么能达到这个结果?

How could I achieve this result?

总是在同一主题上,我有一个REST端点(由Spring Data REST公开),可以使用LocalDate参数进行搜索;我正在使用

Always on the same topic, I've a REST endpoint (exposed by Spring Data REST) to search using LocalDate params; I'm using

@Transactional
@PreAuthorize("isAuthenticated()")
public interface DailyCodeRepository extends PagingAndSortingRepository<DailyCode, Long> {

@Query("SELECT d FROM DailyCode d WHERE (:code IS NULL or code=:code) AND (:from IS NULL OR date>=:from) AND (:to IS NULL OR date<=:to)")
    public Page<DailyCode> findAllWithParameter(@Param("code") @RequestParam(value = "code", required = false) String code,
            @Param("from") @RequestParam(value = "from", required = false) LocalDate from,
            @Param("to") @RequestParam(value = "to", required = false) LocalDate to, Pageable pageable);
}

在这种情况下,我还有一个奇怪的事情:如果我调用端点传递参数,则它们在服务器中的到达时间要短1天.此外,接受的日期模式似乎是我的区域设置(意大利语)的JDK默认设置,但我认为这不是最佳实践.

Also in this case I've a strange thing: if I call the endpoint passing parameters, in the server they arrive with 1 day less. Furthemore the date pattern accepted seems to be the JDK default of my locale (Italian) but I guess it's not a best practice.

是否有最佳实践来避免双向日期/时间参数出现任何问题?

Is there a best practice to follow to avoid any problems with date/time arguments in both direction?

推荐答案

我同意本文的作者

I agree with the author of this article The 5 laws of API dates and times that we have to store and return time in UTC. And 'front-end' must decide itself how to convert the time value depending on the client time-zone.

要实现这一点(以UTC存储和返回时间),我们设置JVM参数-Duser.timezone=UTC或在application.properties中添加spring.jpa.properties.hibernate.jdbc.time_zone=UTC(从Hibernate 5.2.3.Final开始).然后将实体的时间字段从LocalDateTime(不存储时区信息)更改为ZonedDateTime类型.

To achieve this (store and return time in UTC) we set JVM parameter -Duser.timezone=UTC or add spring.jpa.properties.hibernate.jdbc.time_zone=UTC to application.properties (starting from Hibernate 5.2.3.Final). Then change time fields of our entities from LocalDateTime (that doesn't store time-zone info) to ZonedDateTime type.

之后,时间值将独立于启动应用程序的计算机的本地时区存储在UTC中,并且SDR将以 ISO8601 形式返回这些值:

After that the time values will be stored in UTC independently from the local time-zone of the computer where the application is started and SDR will return these values in ISO8601 form: 2017-07-02T11:58:10.089Z

但是,如果有必要在特定时区中返回时间值,我们必须在所有时间字段中设置@JsonFormat批注:

But if it's necessary to return time values in the specific time-zone we have to setup @JsonFormat annotation to all of our time fields:

@JsonFormat(timezone = "Europe/Rome", pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
private ZonedDateTime createdDate;

我们可以在应用程序中定义常量TIME_ZONE并将其设置在@JsonFormat批注中:@JsonFormat(timezone = Application.TIME_ZONE, ...).

Our we can define constant TIME_ZONE in our application and set it in @JsonFormat annotations: @JsonFormat(timezone = Application.TIME_ZONE, ...).

然后我们得到以下输出:

Then we get this output:

{
    //...
    "createdDate": "2017-07-02T14:11:45.964+0200",
    //...
}

不幸的是,参数spring.jackson.time-zone(基于我的简短调查)仅影响应用程序中的服务消息,例如:

Unfortunately, parameter spring.jackson.time-zone (based on my short investigation) affects only on service messages in the application, for example:

{
    "timestamp": "2017-07-02T14:14:09.486+0200",
    "status": 404,
    "error": "Not Found",
    "message": "No message available",
    "path": "/users"
}

要以分区"形式在此处获取时间,我们必须在application.properties中正确设置spring.jackson.date-format参数:

To get time here in 'zoned' form we have to set properly spring.jackson.date-format parameter in the application.properties:

spring.jackson.date-format=com.fasterxml.jackson.databind.util.StdDateFormat

这篇关于Spring REST LocalDate UTC一天不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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