不常见的Date使用问题

JavaQ 2017-08-10



问题

最近维护老项目,遇到一个遗留的日期传输问题。A系统远程调用B系统获取申请时间字段,B系统接口返回的申请时间是String类型,结果A、B两个系统显示的申请时间不一样,A系统的申请时间比B系统的提前了14个小时,问题可以通过简单的代码复现。

Date currentDate = new Date();
System.out.println("currentDate:" + currentDate);

String currentDateStr = currentDate.toString();
System.out.println("currentDateStr:" + currentDateStr);

long numberOfMilliseconds = currentDate.getTime();
System.out.println("numberOfMilliseconds:" + numberOfMilliseconds);

Date receivedCurrentDate = new Date(currentDateStr);
System.out.println("receivedCurrentDate:" + receivedCurrentDate);

Date correctCurrentDate = new Date(numberOfMilliseconds);
System.out.println("correctCurrentDate:" + correctCurrentDate);
输出结果:

currentDate:Sun Aug 06 15:47:08 CST 2017
currentDateStr:Sun Aug 06 15:47:08 CST 2017
numberOfMilliseconds:1502005628392
receivedCurrentDate:Mon Aug 07 05:47:08 CST 2017
correctCurrentDate:Su...



问题

最近维护老项目,遇到一个遗留的日期传输问题。A系统远程调用B系统获取申请时间字段,B系统接口返回的申请时间是String类型,结果A、B两个系统显示的申请时间不一样,A系统的申请时间比B系统的提前了14个小时,问题可以通过简单的代码复现。

Date currentDate = new Date();
System.out.println("currentDate:" + currentDate);

String currentDateStr = currentDate.toString();
System.out.println("currentDateStr:" + currentDateStr);

long numberOfMilliseconds = currentDate.getTime();
System.out.println("numberOfMilliseconds:" + numberOfMilliseconds);

Date receivedCurrentDate = new Date(currentDateStr);
System.out.println("receivedCurrentDate:" + receivedCurrentDate);

Date correctCurrentDate = new Date(numberOfMilliseconds);
System.out.println("correctCurrentDate:" + correctCurrentDate);
输出结果:

currentDate:Sun Aug 06 15:47:08 CST 2017
currentDateStr:Sun Aug 06 15:47:08 CST 2017
numberOfMilliseconds:1502005628392
receivedCurrentDate:Mon Aug 07 05:47:08 CST 2017
correctCurrentDate:Sun Aug 06 15:47:08 CST 2017
分析这个问题之前,先了解一些时间概念及关系。

格林尼治标准时间

格林尼治标准时间(Greenwich Mean Time,简称GMT)指位于英国伦敦郊区的皇家格林尼治天文台当地的标准时间,因为本初子午线被定义为通过那里的经线。理论上来说,格林尼治标准时间的正午是指当太阳横穿格林尼治子午线时(也就是在格林尼治上空最高点时)的时间。但由于地球在它的椭圆轨道里的运动速度不均匀,这个时刻可能与实际的太阳时有误差,最大误差达16分钟。原因在于地球每天的自转是有些不规则的,而且正在缓慢减速,因此格林尼治时间基于天文观测本身的缺陷,已经不再被作为标准时间使用。现在的标准时间,是由原子钟报时的协调世界时(UTC)来决定。

世界协调时

世界协调时(Coordinated Universal Time,简称UTC)又称世界标准时间或世界协调时间,是最主要的世界时间标准,其以原子时秒长为基础,在时刻上尽量接近于格林尼治标准时间。对于大多数用途来说,UTC时间被认为能与GMT时间互换,基本相等,但GMT时间已不再被科学界所确定。

CST

CST代表了4个不同的时间,每个时间和UTC之间的转换关系如下:
中部标准时区(北美洲),Central Standard Time,UT-6:00
澳洲中部时间,Central Standard Time,UT+9:30
北京时间,China Standard Time,UT+8:00
古巴标准时间,Cuba Standard Time,UT-4:00

new Date()

public Date() {
    this(System.currentTimeMillis());
}

public Date(long date) {
    fastTime = date;
}
System.currentTimeMillis()返回当前时间与协调世界时1970年1月1日午夜之间的时间差(以毫秒为单位测量),使用的是UTC。直接输出currentDate会调用toString方法,会根据所在的时区格式化输出日期,所以输出的是Sun Aug 06 15:47:08 CST 2017,格式化成CST时间。

输出的numberOfMilliseconds是从1970年1月1日00:00:00 GMT以来,该Date对象表示的毫秒数,也就是获取到的时间差。

new Date(currentDateStr):

@Deprecated
public Date(String s) {
    this(parse(s));
}

public Date(long date) {
    fastTime = date;
}
Date(String s)这个构造方法已经被标记为过时,不推荐使用。通过解析currentDateStr返回一个long类型的时间差(UTC时间)来构造日期对象,但这个解析的过程中,如果遇到CST,会被认为是指北美的时区,比格林威治时间晚6个小时,按照上面的转换关系,转成UTC需要加6个小时。而在输出receivedCurrentDate的时候会调用toString方法,会根据所在的时区格式化输出日期,也就是将UTC转成China Standard Time,需要加8个小时,所以就出现了相差14个小时。

new Date(numberOfMilliseconds),这个构造方法因为中间没有经过转换,所以再次构造的日期是正确的。

总结

Date实现了java.io.Serializable,是可序列化的,可直接传输,不要传输其字符串数值。
显示全文

查看更多主题的豆瓣日记和相册

JavaQ
作者JavaQ
5日记 0相册

全部回应 0 条

添加回应

JavaQ的热门日记

值得一读

    豆瓣
    我们的精神角落
    免费下载 iOS / Android 版客户端