夏令时踩坑记录
记录一个数据上传下载夏令时踩坑经历。客户端将数据上传到平台,客户端再下载该数据,发现人的生日居然变成了前一天的23点,相差1小时
一、时区说明
Asia/Shanghai: 兼容夏令时,下面简称 "上海"
GMT+8: 不兼容夏令时,比夏令时时间慢一个小时, 下午简称"东八"
二、转换丢失一小时说明
假设有个时间为1991-08-08 00:00:00 的date对象,当前jvm时区 为 "上海"
(1)用"上海"时区来转换,其时间还是1991-08-08 00:00,因为时区一样
(2)用"东八"来转换时,如果是基于时间戳或者是Date对象进行转换,那么时间变成了 1991-08-07 23:00
(3)只要时区不一致,夏令时就存在 +1 或者 -1的问题
三、客户端上传分析
代码分析:
整理流程如下
(1)获取客户端上传的加密的xml
(2)xml解密
(3)交给SpringMVC消息转换器将xml转换成对象,这里用自定义xml中Date类型适配器,底层的DateUtils用系统默认时区进行转换
(4)将Date保存到数据库
特别说明:客户端上传的生日是标准的 yyyy-MM-dd
通过分析可知: 上传过程没有发生过时区转换,且由于时间用的字符串传输,不可能出现时间发生改变的问题
生产环境参数:
(1)springboot项目的application.yml中配置了GMT+8 但这个配置只对jackSon生效,上传过程没有用到jackson,所以这个GMT+8不影响
(2)由于上传过程中客户端传的是字符串,而不是时间戳。字符串天然就屏蔽了这种时区问题
(3)客户端时区GMT+8,通过客户端同事用代码获取一个夏令时的时间戳推导出时区为GMT+8
(4)jvm默认用了上海
虽然客户端用的GMT+8而jvm用的上海,但是传输用的字符串,客户端和服务端之间的传输和时区没关系
小结:
上传过程中: 由于时间使用字符串传输,客户端,服务端时区均不会影响上传结果
四、客户端下载代码分析
代码分析:
整体流程
(1)Controller返回java对象,对象里面的生日用的系统默认时区
(2)通过web过滤器,获取到Response对象从对象取出返回的json
(3)上面的这个json,其实是java对象(Date)通过jackson消息转换器转换成了json字符串,这个jackson的转换用的是yml中配置的时区
(4)json-->java 对象(Date)转换,用了fastjson,用的系统默认时区
(5)java对象-->xml, 用了系统默认时区
(6)加密返回给客户端
特殊说明:返回给客户端时,时间用的是yyyy-MM-dd HH:mm:ss字符串格式
分析:
-- (3)中java对象转jackson 用的yml中配置的时区
-- (4)(5)这个环节,没有发生过时区转换,这个环节时间不会变。
意味着客户端看到的时间内容,就是(4)中java对象的时间内容
-- (3)->(4)这个环节,用的是系统默认时区来转的,说明(4)中java对象的时间内容就是(3)中json字符串里面的时间内容
-- 如果(1)->(3)的这个java对象转json时,存在时区转换,则会导致(3)中json串中的时间和(1)java对象时间不一致
生产环境参数:
(1)yml中配置了GMT
(2)jvm没有配置,则默认用了上海
(3)客户端用的东八区
(4)时间用的字符串来传输
下载时间不对原因及解决方案:
原因:
-- 由于系统用的上海,而yml中配置为GMT+8,导致代码中的(1)->(3)发生了 上海-->GMT+8的时区转换
-- 上海转到GMT+8 夏令时会丢 1小时
解决方案:
yml配置为上海,且系统必须保证为上海
五、总结
(1)上传过程中,时间用字符串传输,不存在时区转换,不会有问题
(2)下载过程,yml时区如果和jvm系统时区不一致时,会发生时区转换。不是加1小时,就是减一小时。
(3)yml时区和系统时区必须保持一致
(4)建议yml中配置上海,然后用java代码在SpringBoot启动类中添加项目启动后把系统默认时区设置为上海,参考下面代码
@PostConstruct public void init () { TimeZone.setDefault(TimeZone.getTimeZone(ZoneId.of("Asia/Shanghai"))); }
六、后记
由于一些特殊的夏今时日期(如1948-05-01) 在idk不的版本Date值不同,把系统和yml时区强制设置成GMT+8 解决这个夏令时的问题
作者:zeng1994
出处:http://www.cnblogs.com/zeng1994/
本文版权归作者和博客园共有,欢迎转载!但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接!