Spring Boot - Jackson - 日期时间时区问题

zFr*_*eak 5 timezone spring datetime jpa jackson

我在处理项目中的时区时遇到问题。

首先,我有两个用例:

1) 用户使用 HTML 中的日期选择器输入一个日期时间,我们希望将其保存在数据库中,但不包含时区。示例输入:10.04.2018 18:00 --> 我们想要准确保存这个日期,并且想要准确检索这个日期,无论客户端的时区是什么。(我们可以把它想象成一个永不改变的日期字符串)

2)更常见的第二个用例是,我们在 HTML 中使用日期选择器输入日期时间,并希望将带有时区的日期保存在数据库中。例如:客户时区是欧洲/伊斯坦布尔,他输入日期时间:10.04.2018 18:00。现在我们想在数据库中将此日期保存为 Europe/Berlin,即 10.04.2017 17:00。当我们检索日期时,我们希望将日期转换为客户端的时区。在此示例中,如果时区为 Europe/Berlin 的客户端想要检索数据库日期 10.04.2017 17:00,我们将准确检索:10.04.2017 17:00。但是,如果时区为 Europe/Istanbul 的客户端想要检索相同的值 10.04.2017 17:00,我们将检索:10.04.2018 18:00

现在,我尝试通过将 web 应用程序时区设置为欧洲/柏林并使用客户端站点上的 Moment.js 库解析每个用例的日期来实现此行为。因此,我总是希望从我的网络服务中检索欧洲/柏林时区的日期,然后转换为本地时区或保留日期不变。

我正在使用以下版本的 Spring Boot:

    <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.9.RELEASE</version>
</parent>
<properties>
    <java.version>1.8</java.version>
</properties>
Run Code Online (Sandbox Code Playgroud)

在我的 application.properties 文件中,我设置了这些值:

spring.jpa.properties.hibernate.jdbc.time_zone=Europe/Berlin
spring.jackson.deserialization.adjust-dates-to-context-time-zone=false
spring.jackson.time-zone=Europe/Berlin
Run Code Online (Sandbox Code Playgroud)

我的应用程序:

@PostConstruct
void started() {
   TimeZone.setDefault(TimeZone.getTimeZone("Europe/Berlin"));
}
Run Code Online (Sandbox Code Playgroud)

我的模型类中的属性如下所示:

@Column(name = "timeFrom")
@Temporal(TemporalType.TIMESTAMP)
private Date timeFrom;

@Column(name = "timeTo")
@Temporal(TemporalType.TIMESTAMP)
private Date timeTo;
Run Code Online (Sandbox Code Playgroud)

对于第一个用例,我想要一个未解析为本地时区的日期,我使用此代码在 javascript 中检索我的日期:(因为我知道数据库中的日期是欧洲/柏林,所以我将其转换为此时区,以便检索与数据库中完全相同的日期)

var countHours = moment(timeTracking["countHours"]).tz('Europe/Berlin').format('HH:mm');
Run Code Online (Sandbox Code Playgroud)

对于第二个用例,我想将欧洲/柏林日期从数据库转换为本地客户端时区,我使用以下代码:

var timeFrom = moment(timeTracking["timeFrom"]).format('YYYY-MM-DD HH:mm');
Run Code Online (Sandbox Code Playgroud)

当我通过 JSON 和 ajax 将日期从 javascript 传递到我的后端时,我使用这个:

moment($("#timeRecord-timeFrom").val()).valueOf()
Run Code Online (Sandbox Code Playgroud)

在服务器端,我收到一个以毫秒为单位的时间戳,然后像这样解析它:

Date dateFrom = new Date(node.get("startTime").asLong());
Run Code Online (Sandbox Code Playgroud)

现在奇怪的部分是:我上面发布的所有内容都在我的本地主机(本地计算机)上运行得很好。然而,当我将 war 文件推送到实时系统(Jelastic Spring Boot 服务器)时,我的日期就有了 2 小时的偏移。

最奇怪的部分是当我通过 ajax 提交日期并在之后检索持久对象时,一切都很好并且我没有偏移量。但是当我重新加载整页时,我立即收到偏移 2 小时的日期。但是,数据库中的日期仍然是正确的。

由于这仅发生在实时系统上,而不是在本地主机上,因此我不知道如何解决此问题。

我究竟做错了什么?切换到 JodaTime 还是 Java8 LocalDateTime 会更好吗?我已经尝试过,但遇到了几个构建错误,所以坚持使用 java.util.Date。

我的用例的最佳实践教程也将受到赞赏。