`
吃猫的鱼
  • 浏览: 45501 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

一个容易被忽视的Java整数溢出错误:无法正确获得年份之差的原因

阅读更多
   随着计算机以及编程语言的不断发展,或许我们现在对于各种类型变量的上限已经不如C语言中的那么敏感。例如,int类型(整型)的变量,它的上限值已经远远超过以前C语言中的整型变量的上限。在一个典型的C语言中,int型变量的范围为-32768~32767,而在java中,int型的变量的范围就达到了-2147483648 到2147483647。因此,通常情况下,我们不用考虑溢出问题。但是,最近我在使用java计算时间差的时候,却遇到了一个诡异的错误,经过一段时间的检查,才发现居然是整型溢出的错误。
    例如,我们现在打算计算两个时间点的年份之差,虽然有很多的函数能够帮我们解决这个问题(例如,先都取出年份值,再相减)。但是也可以直接通过两个时间点之间的数值差(因为,时间类型的数据在计算机中实际上是以long型的数值来存储的),来计算这种时间差。下面演示的是错误的代码:
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
Date date = sdf.parse("2008-05-24 00:00:00");
Date date2 = sdf.parse("2009-05-24 00:00:00");  
System.out.println((date2.getTime()-date.getTime())/((long)(1000*3600*24*365)));

   其中,这段代码的最主要思想就是利用时间点2(date2)的数值,减去时间点1(date)的数值,然后除以1000,将毫秒数值转为秒;再除以3600*24,转为天;最后除以365转成年。代码的逻辑上是没有错误的(当然,严格上来说,应该区分365天或是366天,因而计算年份差是不推荐这么做的),但是执行的时候却总是出错,得到的结果为21!明眼人应该一下子就能够看出这两个时间点的年份差为1年吧。于是考虑将最后一行代码改为如下:
System.out.println((date2.getTime()-date.getTime())/((long)(1000*3600*24)));

   发现就能够得到正确的结果:366天。于是再次将代码改为如下:
System.out.println((date2.getTime()-date.getTime())/((long)(1000*3600*24))/365);

   发现就能够得到正确的结果了:1年。但是如果将代码又改为第一种情况,就发现还是计算错误。在这种情况下,最有可能的原因就是变量的溢出问题。我们可以计算一下,1年的毫秒数为:
       1000*3600*24*365 = 31536000000 ms/year
   原来已经远远超过了int型变量的最大值:2147483647了。于是将计算代码改为如下,也能够正确获得结果:
System.out.println((date2.getTime()-date.getTime())/(((long)(3600*24*1000))*((long)(365))));

   看来,虽然计算机的支持能力以及编程语言的发展,已经能够然我们很便捷的使用各种变量,但是有时候还是需要注意一下这些类型变量所支持的范围,避免以为超过范围,造成莫名其妙的溢出错误。
分享到:
评论
1 楼 GOD_yamade 2016-12-17  
1000后面加个L就解决了吧,1000L*3600*24。

相关推荐

Global site tag (gtag.js) - Google Analytics