Java夏令时导致的问题

一、查询报错提示

报错提示: HOUR_OF_DAY: 0 -> 1

二、问题原因

通过网上查找资料得知,是中国有一段时间实施过夏令时导致的 1986-1991年 , 夏令时就是会在春夏之交当中某一天把时钟拨快一个小时的做法, 通过排查数据找到了一个有问题的日期** 1987-04-12 00:00:00这个日期是中国夏令时的开始时间,会在晚上把两点手动调成三点, 不同版本下 Asia/Shanghai 时区夏令时起始时间的不同,正是源于这种穷举配置,早期维护者认为中国标准时间的夏令时切换发生在0时,而后来又经证明发生在2时,新版本 JDK 及时修正了这个问题罢了。 所以mybatis返回时间做严格的校验会认为 1987-04-12**这一天不存在0点,应该直接从一点开始所以报错.

ps: 夏令时

夏令时,(Daylight Saving Time:DST),也叫夏时制,又称“日光节约时制”和“夏令时间”,是一种为节约能源而人为规定地方时间的制度,在这一制度实行期间所采用的统一时间称为“夏令时间”。一般在天亮早的夏季人为将时间调快一小时,可以使人早起早睡,减少照明量,以充分利用光照资源,从而节约照明用电。各个采纳夏时制的国家具体规定不同。全世界有近110个国家每年要实行夏令时。

1986年4月,中国中央有关部门发出“在全国范围内实行夏时制的通知”,具体做法是:每年从四月中旬第一个星期日的凌晨2时整(北京时间),将时钟拨快一小时,即将表针由2时拨至3时,夏令时开始;到九月中旬第一个星期日的凌晨2时整(北京夏令时),再将时钟拨回一小时,即将表针由2时拨至1时,夏令时结束。从1986年到1991年的六个年度,除1986年因是实行夏时制的第一年,从5月4日开始到9月14日结束外,其它年份均按规定的时段施行。在夏令时开始和结束前几天,新闻媒体均刊登有关部门的通告。1992年起,夏令时暂停实行。

优点

高纬度地区由于夏季太阳升起时间明显比冬季早,夏令时确实起到节省照明时间的作用。

Java 夏令时偏移量 java夏令时问题解决_Java 夏令时偏移量

正在调时间适应夏令时的工人

不少零售商对夏令时持肯定态度。美国的糖果商院集团已经游说美国国会将夏令时延长到11月,因为万圣节是糖果销售最旺的季节,而家长们不希望孩子们在天黑以后还在外面游逛。

有人认为夏令时对患有夜盲症的人大有好处。除了节约了电,也让人们养成了早睡早起的好习惯

弊端

低纬度地区,夏令时作用不大。尤其这些地方在夏天十分湿热,夜晚降临时闷热无法入眠,而清晨正是睡眠的好时间。

当夏令时开始和结束时,人们必须将所有计时仪器调快或调慢;当夏令时结束时,某些时间会在当天出现两次,这些都容易构成混乱。并且影响航班的时间。

夏令时违背了设定时区的原意──尽量使中午贴近太阳上中天的时间。

中国实时夏令时开始结束日期

1986年至1991年,每年四月的第2个星期日早上2点,到九月的第2个星期日早上2点之间。

1986年5月4日至9月14日(1986年因是实行夏令时的第一年,从5月4日开始到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日。

三、问题修复方案

  1. 在数据库系统设计时,需要用到精确时间和计算的时候尽量使用 绝对时间, 然后让这个时间在不同的时区和系统中手动转换成本地时间
  2. 在问题复现的过程中发现 OracleJDK没有这个问题,OpenJDK存在这个问题, 开发过程中本地JDK和线上JDK版本尽量保持一致
  3. mybatis查询映射过程中,尽量使用JDK8版本的时间工具类LocalDate 不要使用Date (ps: 这种方式不兼容老的系统)
  4. mybatis查询映射过程中可以使用string类型来接收时间变量,自己手动转为时间类型,不同国家不同时区对同一日期的标识是不同的
  5. 可以通过修改数据库链接的时区来解决这个问题 由 serverTimezone=Asia/Shanghai改为serverTimezone=GMT%2B8

ps: 绝对时间

格林威治时间1970年1月1日0时0分0秒相差的毫秒数