问题现象
将Joda的DateTime转为JDK Date可能会有奇怪的问题,在不同的机器上出现偏差,比如多了半小时、少了一小时。
试验过程
试验代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public class App { public static void main(String[] args) { String time = args[0]; DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("HH:mm:ss"); DateTime dateTime = dateTimeFormatter.parseDateTime(time); System.out.println("DateTime: " + dateTime); Date date = dateTime.toDate(); System.out.println("Date: " + date); System.out.println("========================================="); LocalTime localTime = LocalTime.parse(time, dateTimeFormatter); System.out.println("LocalTime: " + localTime); LocalDateTime localDateTime = dateTimeFormatter.parseLocalDateTime(time); System.out.println("LocalDateTime: " + localDateTime); Date date2 = localDateTime.toDate(); System.out.println("Date from LocalDateTime: " + date2); } } |
使用的joda-time包的version为2.9.3。
输出结果
1 2 3 4 5 6 | DateTime: 1970-01-01T10:00:00.000+08:00 Date: Thu Jan 01 10:30:00 CST 1970 ========================================= LocalTime: 10:00:00.000 LocalDateTime: 1970-01-01T10:00:00.000 Date from LocalDateTime: Thu Jan 01 10:00:00 CST 1970 |
解决方案
使用Joda的LocalDateTime/LocalTime/LocalDateTime
类可以避免此问题。
相反地,从JDK Date转化为Joda DateTime时,在这些机器上存在同样的问题,也可以用样的方法规避。
后来发现,是因为服务器上的/etc/localtime
文件指向的是/usr/share/zoneinfo/Asia/Harbin
,从而导致序列化Date时出现时区偏差。
Java通过/usr/share/zoneinfo/Asia/Harbin
的文件名来确定时区,而系统命令date
是通过文件内容来确定的,因此结果不同。
解决方法是
1 | ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime |
此方法在CentOS 6.5系统上验证,这里不能使用cp
命令将文件复制过来,否则Java程序可能会出问题。
参考资料:
- Date类型字段反序列化后值发生变化问题: /solution/date-serialize-bug-timezone/
- CentOS7修改时区的正确姿势: https://blog.csdn.net/yin138/article/details/52765089