好的,首先要全面披露。我正在开发一个在其实体和 dto 对象上使用 java.util.Date 的项目,我们正在努力更改为 LocalDateTime。当 Jackson 在控制器层将我们的 dto 对象序列化为 JSON 时,我们自然会遇到时区问题。我们正在努力将日期更改为 LocalDateTime,但在此期间,设置以下属性:
jackson:
time-zone: Canada/Pacific
用于将日期/时间转换为正确的值。但是,我们的应用程序部署为托管在 Openshift 上的 docker 容器。一旦进入 docker,即使在我的本地机器上,我也可以将此值更改为任何值,并且日期永远不会改变。我已经尝试检查 linux 容器中的 TZ 值,它与我们的时区等匹配。有什么想法吗?
java.time.Instant
,而不是java.time.LocalDateTime
。时区没问题。
Instant
,而不是LocalDateTime
在其实体和 dto 对象上使用 java.util.Date,我们正在努力更改为 LocalDateTime
LocalDateTime
是这里使用的错误类。该类故意缺少任何时区或与 UTC 的偏移量的概念。因此,该类的对象不能代表时间轴上的一个时刻、一个特定点。只需一个日期和一天中的某个时间,我们就有办法知道您指的是东京、图卢兹还是托莱多的那个时间——例如,相隔几个小时的三个截然不同的时刻。
替换
java.util.Date
的类是java.time.Instant
。两者都代表一个时刻,时间轴上的一个特定点,如与 UTC 的零时分秒偏移量所示。
👉所以使用
Instant
。您的时区问题完全消失了。
当文本序列化为 JSON、XML 等时,仅使用标准 ISO 8601 格式。在 UTC 中,这会像这样:
2023-04-28T19:31:41.078125Z
。末尾的Z
是+00:00
的缩写,偏移量为零;发音为“祖鲁”。
java.time 类在解析/生成文本时默认使用 ISO 8601 格式。无需指定格式模式。
String output = myInstant.toString() ;
……和:
Instant myInstant = Instant.parse( input ) ;
要通过特定时区的挂钟时间查看那一刻,请应用
ZoneId
以获得ZonedDateTime
。
ZoneId z = ZoneId.of( "America/Vancouver" ) ;
ZonedDateTime zdt = myInstant.atZone( z ) ; // Same moment as the `Instant` object, but different wall-clock time & possibly different date.
在此代码中,
myInstant
和 zdt
都代表同一时刻,即时间轴上的同一时间点。就像在不列颠哥伦比亚省温哥华和雷克雅未克冰岛互相打电话的两个人一样,如果两个人同时抬头看各自墙上的日历和时钟,他们会看到一天中的不同时间,甚至可能是不同的日期。
当 Jackson 序列化我们的 dto 时,我们自然会遇到时区问题
你是unnecessarily introducing time zone where it is not needed.
注意上面的代码是如何不依赖于默认时区的。编写代码以避免隐式依赖于 JVM 当前的默认时区。始终传递可选的时区参数。