问题现象

将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
22
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程序可能会出问题。

参考资料: