1、问题描述
近期在SpringBoot+Mybatis的项目中发现从数据库选择出来的时间记录对不上实际时间。我的数据库使用的是PostgreSQL,其中有一些表使用了timestamp(6) without time zone字段来存储时间,在Mybatis映射时为了能够满足中国时区时间与时间格式的统一在JavaBean的时间属性上使用@JsonFormat注解。但是出现了诡异的情况:选择返回的时间与数据库存储记录的时间对不上。
如:
数据库存储的记录:
create_time: 2021-02-13 12:14:49
经Mybatis提取并返回前端的Json:
"createTime":"2021-02-13 12:02:00"
2、解决问题
经过一步步排查之后,发现问题可能出现在@JsonFormat注解pattern字段上。
原代码:
@JsonFormat(pattern = "yyyy-MM-dd HH:MM:SS", timezone = "GMT+8")
private Date createTime;
修改后的代码:
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
3、原因剖析
yyyy-MM-dd HH:MM:SS这种日期格式并不合适:在分钟位使用MM,解析时会被误以为是月份,从而将14分解析为02【12+2个月】,而在秒钟位使用SS,解析时并无法解析,因此无论什么时间都是00。
4、时间字符串格式说明
常用格式:
yyyy-MM-dd HH:mm:ss 24小时制
yyyy-MM-dd hh:mm:ss 12小时制
字段 | 说明 |
---|---|
y | 不包含纪元的年份。不具有前导零。 |
yy | 不包含纪元的年份。具有前导零。 |
yyyy | 包括纪元的四位数的年份。 |
M | 月份数字。一位数的月份没有前导零。 |
MM | 月份数字。一位数的月份有一个前导零。 |
MMM | 月份的缩写名称,在 AbbreviatedMonthNames 中定义。 |
MMMM | 月份的完整名称,在 MonthNames 中定义。 |
d | 月中的某一天。一位数的日期没有前导零。 |
dd | 月中的某一天。一位数的日期有一个前导零。 |
ddd | 周中某天的缩写名称,在 AbbreviatedDayNames 中定义。 |
dddd | 周中某天的完整名称,在 DayNames 中定义。 |
gg | 时期或纪元。 |
h | 12 小时制的小时。一位数的小时数没有前导零。 |
hh | 12 小时制的小时。一位数的小时数有前导零。 |
H | 24 小时制的小时。一位数的小时数没有前导零。 |
HH | 24 小时制的小时。一位数的小时数有前导零。 |
m | 分钟。一位数的分钟数没有前导零。 |
mm | 分钟。一位数的分钟数有一个前导零。 |
s | 秒。一位数的秒数没有前导零。 |
ss | 秒。一位数的秒数有一个前导零。 |
f | 秒的小数精度为一位。其余数字被截断。 |