一、问题描述

前段时间遇到一个很神奇且费解的问题,程序将用户的生日从日期类型转为string类型时,竟然莫名其妙的少了一天,具体表现为存在数据库的19900916这个日期,取出到程序后做转换为字符串的操作,然后神奇的变为了19900915,并且在开发环境重现时出现了有些同事能够重现,而有些同事无法复现的情况。最终,我们发现了问题的原因,真的可谓是你意想不到的坑之一。
如下图为问题复现:

可见19900906经过日期转换后依然为

Sun Sep 16 00:00:00 CDT 1990

但是获取时间戳,再通过时间戳进行时间转换的时候日期就变成了

1990-09-15T08:23:00.000+08:00

可以看出,时间少了一个小时,如果只看年月日的话就是日期少了一天。

二、夏令时制度

在解答这个问题的时候,不得不先介绍夏令时的概念

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

而且中国也有一段时间实行过夏令时制度,惊喜吧。

我国解放前几年在部分地区也曾实行过夏令时。1986年4月,中央有关部门发出“在全国范围内实行夏时制的通知”,具体作法是:每年从四月中旬第一个星期日的凌晨2时整(北京时间),将时钟拨快一小时,即将表针由2时拨至3时,夏令时开始;到九月中旬第一个星期日的凌晨2时整(北京夏令时),再将时钟拨回一小时,即将表针由2时拨至1时,夏令时结束。从1986年到1991年的六个年度,除1986年因是实行夏时制的第一年,从5月4日开始到9月14日结束外,其它年份均按规定的时段施行。1992年起,夏令时暂停实行。
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月中旬的第一个星期日2时起至9月中旬的第一个星期日2时止。具体如下:
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小时,即:将调快的1小时减回来。因此,如为实行夏时制时期出生,如当时记录的出生时间是夏令时,请注意将夏令时前推一小时方为实际出生时间。
例如夏令时公历1991年5月2日0点10分出生,则将夏令时换算为正常时间即 1991年5月1日23点10出生。
看来,如果用户生日假如真的是1990-09-16 00:00:00,并且这个时间为夏令时的话,那么他的生日确实是1990-09-15 23:00:00。可是用户才不会听你解释什么夏令时,你给他把生日计算错了,他就会投诉你。接下来在让我们看看java程序为什么会算错呢?

原来java的Date类型遵循Unix时间规则,将1970-01-01 00:00:00为世界纪元起点,以毫秒为单位。内部存放的Time为long型,返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。当我们使用中国夏令时获取到的long型时间,然后使用toString()做转换的时候java自动减少了一小时,也就获得了之后不正确的时间。

三、jdk版本区别

加入真的有这个坑的话,为什么我们最近才发现,之前一直没有遇到过呢,并且我们为什么有些人能够复现,有些人却复现不了呢?带着这个问题,我们继续追查,最终发现原来是jdk版本的差别。
大家注意上面那个有问题的是基于jdk1.8.0_201,而下列这张图是基于jdk1.8.0_131的,就没有出现该类问题,可以推测比jdk1.8.0_201的版本可能都有此类问题。所以难道是jdk版本升级内置了对于中国夏令时那段时间的支持?如果真是如此的话,不得不佩服jdk开发人员的细致程度,但也给我带来了一次不大不小的坑。

四、解决方法

1.使用SimpleDateFormat.format的方法没发现有此类问题
2.使用Calendar类,虽然繁琐一点
3.最推荐的方法:

设置应用的
TimeZone.setDefault(TimeZone.getDefault().getTimeZone("GMT+8"));
或加启动参数
-Duser.timezone=GMT+8

附一张使用GMT(格林尼治标准时间-也叫世界时)的结果图

谢谢阅读,希望你能避免此坑~

---------------------------------------------------------------------------------我是分割线--------------------------------------------------------------------------
to be a better me, talk is cheap show me the code

版权所有,转载请注明原文链接。

文中有不妥或者错误的地方还望指出,以免误人子弟。如果觉得本文对你有所帮助不妨【点赞】一下!如果你有更好的建议,可以给我留言讨论,共同进步!

再次感谢您耐心的读完本篇文章。


那些年我们踩过的坑——Java中Date夏令时日期转换不一致问题相关推荐

  1. java 夏令时 重置偏移量_那些年我们踩过的坑——Java中Date夏令时日期转换不一致问题...

    一.问题描述 前段时间遇到一个很神奇且费解的问题,程序将用户的生日从日期类型转为string类型时,竟然莫名其妙的少了一天,具体表现为存在数据库的19900916这个日期,取出到程序后做转换为字符串的 ...

  2. 那些年我们踩过的坑,SQL 中的空值陷阱!

    那些年我们踩过的坑,SQL 中的空值陷阱! 置顶 不剪发的Tony老师 2019-12-31 07:31:17 6737 收藏 66 分类专栏: SQL 文章标签: sql 空值 mysql orac ...

  3. 最新Java中Date类型详解

    一.Date类型的初始化 1. Date(int year, int month, int date); 直接写入年份是得不到正确的结果的. 因为java中Date是从1900年开始算的,所以前面的第 ...

  4. [转载]java中Date,SimpleDateFormat

    一.Java中的日期概述: 日期在Java中是一块非常复杂的内容,对于一个日期在不同的语言国别环境中,日期的国际化,日期和时间之间的转换,日期的加减运算,日期的展示格式都是非常复杂的问题. 在Java ...

  5. Java中Date各种相关用法

    Java中Date各种相关用法 本文主要介绍Java中Date各种相关用法. AD:   Java中Date各种相关用法(一) 1.计算某一月份的最大天数 Java代码 Calendar time=C ...

  6. java中Date,SimpleDateFormat

    一.Java中的日期概述: 日期在Java中是一块非常复杂的内容,对于一个日期在不同的语言国别环境中,日期的国际化,日期和时间之间的转换,日期的加减运算,日期的展示格式都是非常复杂的问题. 在Java ...

  7. java date linux,Java中Date,SimpleDateFormat

    一.Java中的日期概述: 日期在Java中是一块非常复杂的内容,对于一个日期在不同的语言国别环境中,日期的国际化,日期和时间之间的转换,日期的加减运算,日期的展示格式都是非常复杂的问题. 在Java ...

  8. java中Date日期类型的大小比较

    java中Date日期类型的大小比较 方法一: java.util.Date类实现了Comparable接口,可以直接调用Date的compareTo()方法来比较大小 String beginTim ...

  9. Java中Date和Calender类的使用方法

    查看文章     Java中Date和Calender类的使用方法 2009-10-04 20:49 Date和Calendar是Java类库里提供对时间进行处理的类,由于日期在商业逻辑的应用中占据着 ...

  10. java中date和时间戳相互转换以及获取前一个小时的时间

    1.时间戳是指文件属性里的创建.修改.访问时间. 数字时间戳技术是数字签名技术一种变种的应用.在电子商务交易文件中,时间是十分重要的信息.在书面合同中,文件签署的日期和签名一样均是十分重要的防止文件被 ...

最新文章

  1. LINUX驱动注册过程失败处理不当引起的恶果
  2. HDU 1426 Sudoku Killer
  3. Linux系统简单介绍和基本命令
  4. VS.NET 2003 安装问题
  5. python飞机大战资料-Python之游戏开发-飞机大战
  6. 当S8遇上边缘计算:谈阿里云ENS对直播业务场景的支撑
  7. java 判断值是否设置,获取Java中“-非法访问”设置的当前值
  8. Java学习日报—Swagger介绍 与 布隆过滤器详解—2021/12/01
  9. 如何保养与维护笔记本硬盘
  10. php开发v2ex,继续求 PHP 开发工作
  11. matlab isnumeric函数,matlab中isnan函数
  12. xampp 2016支持php7.0,xampp 装php7
  13. cocos2d-iphone 3.X 进度条的实现
  14. 马哥linux脚本,马哥linux shell笔记
  15. SQLite3下载与安装
  16. 由2003年的一篇讲座笔记
  17. 从零开始写渲染Step1窗口的创建和显示
  18. IE浏览器网址被劫持
  19. element-ui upload 多个文件一次请求上传(Vue精简版)
  20. “宅一族”大数据报告:喜欢学习,喜欢健身,生活同样很精彩

热门文章

  1. linux路由表怎么看懂,教你读懂Linux路由表
  2. Tibco Designer -- 构建EAR文件
  3. 百宝云COM组件操作教程
  4. ROS-3DSLAM(十四)lvi-sam源代码阅读12 —— visual_loop阅读5
  5. 计算图像中任意四个点连成的四边形面积与Ground truth的IOU(Python)
  6. 第11章-ThreadSpecificStorage
  7. 对微信小程序的一些用法的感悟和总结
  8. 最薄翻转笔记本 联想Yoga13-IFI 6700
  9. http://www.bluecoat.com.cn/resources/overview
  10. 系统创建定时执行任务bat批处理删除指定N天前文件夹的文件