.
问题
有两台Linux机器:
date 命令查看时间相同
通过 date 命令查看时间,发现两台机器区域语言和时间都相同:
JVM获取系统时间相差12小时
通过最基本的java代码 new Date() 获得时间,发现两台机器的系统时间相差12小时。
其中一台输出的时区与上述date命令相同,都是东八区(CST,中国标准时间)。
另一台输出的时区与date命令不符,是西五区(EDT,美国东部白昼时间)。
根据理论经度,东八区 与 西五区 相差13小时。但因为时值美国夏令时,时刻的值被“人为”调整,所以两台机器相差12小时。
解决方法
可以确定那台 date命令所得时区与JVM所得时区不同的 机器时间是错的。
修复方法就是以正确的方式重新设置系统时区:
Shell代码
-
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
扩展
尽量自动化,减少对人肉运维的依赖
上述 date命令所得时区 与 JVM所得时区 不一致的问题,就是因为操作系统的时区未被正确设置。
这往往是不合格的“运维人员”“虎操作”导致的。
这种错误对于需要处理时间的Java应用而言是致命的!!!
不但无法得到正确的系统当前时间,也无法解析历史时间数据。 如,你之前在MySQL中正确存储了一个时间值,在这种错误的系统环境中,JVM解析这个来自数据库的行为也会出错。
此外,如果你的系统需要多台机上的Java应用基于各自的系统时间来合作完成某项业务,那么错误的那台机器会将你的业务逻辑完全破坏。
这种错误还非常难排查,你几乎不会去怀疑系统时区问题,因为date命令显示时区是正确的。
尽量使用维护成本低、准确无歧义的方式表示时间
不要使用时区缩写
时区缩写很可能有歧义。如,CST 可以表示:
-
美国中部时间:Central Standard Time (USA)
-
澳大利亚中部时间:Central Standard Time (Australia)
-
中国标准时间:China Standard Time
-
古巴标准时间:Cuba Standard Time
可以考虑用数值来表示时区。如,+08:00 表示东八区。
不要用夏令时
很多国家有 夏令时 和 冬令时 之分。在夏令时,时刻会被人为调整。
这种做法其实非常得不偿失,应尽量避免去涉及此类问题。
不要用年号纪年法
这也是一种“人祸”,非常浪费社会资源。
日本换个天皇就改个年号,平白浪费了很多社会资源。
这种纪年法展示的信息也与世界标准的公元纪年法格格不入,非常不利于信息交流。
很多非国际公认度量单位也对世界级的信息交流非常不友好,尽量不要使用。如,英尺、加仑、盎司。