业务开发过程中需要对java.util.Date的时间进行设置,使用了void java.util.Date.setTime(long time)方法,但在测试过程中却发现millisecond超过某一定长度后出现了“逆流”,时间出现了回退现象。
现象描述
(1)我们先看一下正常情况下的例子,将当天时间增加10天
public static void main(String[] args) { Date now = new Date(); System.out.println("now time : " + now); now.setTime(now.getTime() + 60 * 60 * 24 * 1000 * 10); System.out.println("next1 time : " + now); }
返回结果如下:
now time : Thu Feb 09 11:26:28 CST 2017 next time : Sun Feb 19 11:26:28 CST 2017
从返回值可以看出时间设置成功,当前时间被往后推了10天。
(2)我们再看一下异常情况的例子,将当前时间增加365天
public static void main(String[] args) { Date now = new Date(); System.out.println("now time : " + now); now.setTime(now.getTime() + 60 * 60 * 24 * 1000 * 365); System.out.println("next2 time : " + now); }
返回结果如下:
now time : Thu Feb 09 11:39:16 CST 2017 next2 time : Sun Feb 26 12:19:45 CST 2017
从结果中可以看出被设置后的时间没有往后累加365天,反而只是加了十几天,时间还是停留在2017年,出现的结果和期望值不一样!
原因分析
仔细对比了两个例子的代码,唯一不一样的地方就是一个时间乘以了10,另一个时间乘以了365,其他代码都是一样的,百思不得其解。
多试了几种异常情况后,发现乘以的天数达到某一阈值后会出现时间回退现象,而在这个阈值之前的设置都是正常的,并且回退出现循环情况。
发现这个规律后,第一想到的就是数据值长度超出某数据类型的最大值后被循环截断了。这时再分析下数据表达式,发现“60 * 60 * 24 * 1000 * 365”这个地方可能存在问题,换一种方式处理后果然验证了猜想!
public static void main(String[] args) { Date now = new Date(); System.out.println("now time : " + now); long addTime = 60 * 60 * 24 * 1000 * 365L; now.setTime(now.getTime() + addTime); System.out.println("next3 time : " + now); }
返回结果正常:
now time : Thu Feb 09 11:51:37 CST 2017 next3 time : Fri Feb 09 11:51:37 CST 2018
现在可以看出,是“60 * 60 * 24 * 1000 * 365”的计算结果被当成int型数据截断了!如果显示的将其标识为long型数据就没有问题了。
这个也提醒我们在处理时间毫秒等长数据类型时一定要显示的使用long型,即使下面这种前置声明方式也会有问题:
public static void main(String[] args) { Date now = new Date(); System.out.println("now time : " + now); long addTime = 60 * 60 * 24 * 1000 * 365; now.setTime(now.getTime() + addTime); System.out.println("next4 time : " + now); }
异常结果:
now time : Thu Feb 09 11:55:45 CST 2017 next4 time : Sun Feb 26 12:36:14 CST 2017
这段测试代码和上一段唯一不一样的地方在于:
long addTime = 60 * 60 * 24 * 1000 * 365L long addTime = 60 * 60 * 24 * 1000 * 365;
通过最后这个例子相信大家已经知道这个时间设置问题的本质原因了!