Loading

JAVA开发使用@JsonFormat注解,日期比实际日期少一天问题

前言

最近同事反馈一个问题,说是日期保存后未发生变化。刚开始以为是字段未对应或者是未保存成功,当我去进行排查的时候发现,发现数据保存没有问题。奇了怪了。

问题现象

库里日期数据保存正确,但是后台返回前台页面发现不正确。

排查过程

刚开始怀疑是数据未保存成功,经过测试发现数据正常保存进数据库中。

有转变方向根据Debug走了一遍数据查询过程,发现问题所在。

后台查询结果正确,但是经过controller层响应前台时,日期发生了变化。OK,问题定位,检查日期格式转换。

发现后台实体中日期转换使用@JsonFormat注解,但是转换格式没有发现问题

@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")

根据网上解决方案调整timezone 与 pattern 的顺序,未成功解决。

最后在一篇文章中找到答案并解决,特来记录这个有意思的小bug。

关于@JsonFormat注解

@JsonFormat注解,是在Jackson中定义的一个注解,是一个时间格式化注解。此注解用于属性上,作用是把DATE类型的数据转化成为我们想要的格式。

通俗点来说,是后台数据转换为指定日期格式返回给前台时使用的。

  • pattern(模式): 通过 pattern 属性,您可以指定日期和时间的格式。
    例如,如果要将日期格式设置为"yyyy-MM-dd",可以使用 @JsonFormat(pattern = "yyyy-MM-dd")
  • timezone(时区): 使用 timezone 属性可以指定日期和时间的时区。这对于确保正确地处理跨时区的日期数据很重要。
  • locale(区域设置): 通过 locale 属性,您可以指定用于格式化的区域设置,以便支持不同的语言和地区。
  • shape(形状): shape 属性定义了序列化后的日期表示形式。例如,您可以将日期表示为字符串或时间戳。
  • with(特定类型的格式): 使用 with 属性,您可以为不同的 Java 类型指定不同的格式。这对于处理不同类型的日期数据非常有用。

注意:我们在格式化的时候要指定时区(timezone ),是因为@JsonFormat注解默认的时区为格林尼治时间,比中国时间(东八区是要小8个小时的)。

中国的默认时区是东八区

时区概念

GMT:Greenwich Mean Time 格林尼治标准时间。这是以英国格林尼治天文台观测结果得出的时间,这是英国格林尼治当地时间,这个地方的当地时间过去被当成世界标准的时间。

UT:Universal Time 世界时。根据原子钟计算出来的时间。

UTC:Coordinated Universal Time 协调世界时。因为地球自转越来越慢,每年都会比前一年多出零点几秒,每隔几年协调世界时组织都会给世界时+1秒,让基于原子钟的世界时和基于天文学(人类感知)的格林尼治标准时间相差不至于太大。并将得到的时间称为UTC,这是现在使用的世界标准时间。

协调世界时不与任何地区位置相关,也不代表此刻某地的时间,所以在说明某地时间时要加上时区

也就是说GMT并不等于UTC,而是等于UTC+0,只是格林尼治刚好在0时区上。

GMT = UTC+0

格林尼治时间(GMT)、世界协调时间(UTC)和中国时间的关系

中国时间(Asia/Shanghai) = 格林尼治时间(GMT) + 8
格林尼治时间(GMT) = 世界协调时间(UTC) + 0

问题原因

中国在1986年至1991年实行过夏令时,即在这些年份北京时间比GMT提前9个小时。所以使用注解@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")看起来像是未起作用。

解决方案

使用下面的注解替换@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")

@JsonFormat(pattern = "yyyy-MM-dd", locale = "zh", timezone = "Asia/Shanghai")

参考文章

  1. 解决年份为1986~1991时,使用注解@JsonFormat(pattern = “yyyy-MM-dd“, timezone = “GMT+8“)仍然比实际日期少一天

2.格式化日期注解@JsonFormat的使用和TimeZone时区问题

posted @ 2024-05-11 18:20  三岁6  阅读(847)  评论(0编辑  收藏  举报