一次因JDK夏令时导致接口输出日期格式的时间与预期时间不一致的bug排查总结

环境说明
开始bug排查之前,先说明下项目环境:
bug 排查 从数据层开始查找,先查询数据库时间和时区 。
SQL> SELECT SYSTIMESTAMP, SESSIONTIMEZONE FROM DUAL;SYSTIMESTAMPSESSIONTIMEZONE-------------------------------------------------------------------------------- ---------------------------------------------------------------------------17-JUL-19 02.20.06.687149 PM +08:00+08:00SQL>
数据库时间和时区都没有问题 。
确认操作系统和java进程时区
[test@test ~]$ date -RWed, 17 Jul 2019 16:48:32 +0800[test@test ~]$ cat /etc/timezoneAsia/Shanghai
[test@test ~]$ jinfo 7490 |grep user.timezoneuser.timezone = Asia/Shanghai
可以看出我们操作系统使用的时区和java进程使用的时区一致,都是东八区 。
用debug继续往上层查找查看和JDBC层
查看了问题字段映射字段的类型为="",在中类型处理注册类.java 中对应的处理类为 .java 。
this.register((JdbcType)JdbcType.TIMESTAMP, (TypeHandler)(new DateTypeHandler()));
进一步查看 .java 类:
//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package org.apache.ibatis.type;import java.sql.CallableStatement;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Timestamp;import java.util.Date;public class DateTypeHandler extends BaseTypeHandler {public DateTypeHandler() {}public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException {ps.setTimestamp(i, new Timestamp(parameter.getTime()));}public Date getNullableResult(ResultSet rs, String columnName) throws SQLException {Timestamp sqlTimestamp = rs.getTimestamp(columnName);return sqlTimestamp != null ? new Date(sqlTimestamp.getTime()) : null;}public Date getNullableResult(ResultSet rs, int columnIndex) throws SQLException {Timestamp sqlTimestamp = rs.getTimestamp(columnIndex);return sqlTimestamp != null ? new Date(sqlTimestamp.getTime()) : null;}public Date getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {Timestamp sqlTimestamp = cs.getTimestamp(columnIndex);return sqlTimestamp != null ? new Date(sqlTimestamp.getTime()) : null;}}
因为使用的数据源为Druid,其中 ( rs,) 方法参数中 使用了.java 的 ( ),通过列名称获取值然后转换为Date类型的值 。

一次因JDK夏令时导致接口输出日期格式的时间与预期时间不一致的bug排查总结

文章插图
【一次因JDK夏令时导致接口输出日期格式的时间与预期时间不一致的bug排查总结】由上图debug看到是JDK中的类,也就是说这里看到的是JDK使用的时间和时区,从图中标注2处可以看出JDK使用的时区也是东八区,但是从1和3处看起来似乎有点不一样,首先1处变化为UTC/GMT+0900,3处有一个的这样一个时间,换算为小时刚好为1个小时 。这个值通过搜索知道叫做夏令时 。
常用时间概念 UTC,GMT,CST,DST
中国夏时制实施时间规定(夏令时) 1935年至1951年,每年5月1日至9月30日 。1952年3月1日至10月31日 。1953年至1954年,每年4月1日至10月31日 。1955年至1956年,每年5月1日至9月30日 。1957年至1959年,每年4月1日至9月30日 。1960年至1961年,每年6月1日至9月30日 。1974年至1975年,每年4月1日至10月31日 。1979年7月1日至9月30日 。1986年至1991年,每年4月中旬的第一个星期日1时起至9月中旬的第一个星期日1时止 。具体如下: 1986年4月13日至9月14日,1987年4月12日至9月13日,1988年4月10日至9月11日,1989年4月16日至9月17日,1990年4月15日至9月16日,1991年4月14日至9月15日 。