我刚刚在我正在开发的一个网站上发现了一个错误,我纠正了它。我的问题是,即使我纠正了,我也不明白问题出在哪里。
我有两个日期(我不能使用GregorianCalendar),我想用天来评估这两个日期之间的距离。这有点琐碎,但我的代码有一个奇怪的行为。
对于特定的日期,例如:2008年4月26日和2008年5月26日,天数应该正好是30天,但我得到了-19天。对于其他日期,它运行良好。以下是我所做的:
Date dMin = ... // -> 26/04/2008
Date dMax = ... // -> 26/05/2008
System.out.println((dMax.getTime()-dMin.getTime())/(1000*60*60*24)); // prints 30
int i = (int) (dMax.getTime()-dMin.getTime())/(1000*60*60*24); // i = -19
那么我是如何纠正的呢?我做了这样的事:
long i = (dMax.getTime()-dMin.getTime())/(1000*60*60*24);
后来,就在我把它显示在屏幕上之前,我会把它转换成一个整数,它运行得很好。
我正在使用GWT,这个演算是在客户端完成的(所以它被编译为javascript)。
那里有我遗漏的东西吗?我想是的,但我找不到它是什么。
我认为您的强制转换(括号)有问题,例如:
public static void main(String[] args) throws Exception {
System.out.println((int)(1.2)*10); //prints 10
System.out.println((int)(1.2*10)); //prints 12
}
因此,int i = (int) (dMax.getTime()-dMin.getTime())/(1000*60*60*24); // i = -19
在除法之前首先将dMax.getTime()-dMin.getTime()
强制转换为int,可能会出现溢出。
Date.getTime()
返回long
。一个月是(24*60*60*1000*30=)2592000000毫秒。这个值需要32位,因此它不适合无符号整数(其最高值为231-1)。因此,当您在将dMax.getTime()-dMin.getTime()
除以1000*60*60*24
之前将其强制转换为int
时,会出现无声溢出错误,截断的结果将被解释为负的int
值。
除法之后,结果已经足够小,可以放入int
,因此在强制转换时没有溢出,最终结果是正确的。
Joda时间
如果您使用一个好的日期时间库,如JodaTime或JSR310/Java 8,这种工作会更容易、更可靠。
示例代码
以下是Java 7中Joda Time 2.3中的一些示例代码。
// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// import org.joda.time.*;
// import org.joda.time.format.*;
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" );
DateTime start = new DateTime(2008, 4, 26, 0, 0, 0, timeZone);
DateTime stop = new DateTime(2008, 5, 26, 0, 0, 0, timeZone);
int daysBetween = Days.daysBetween( start, stop ).getDays();
转储到控制台…
System.out.println( "start: " + start );
System.out.println( "stop: " + stop );
System.out.println( "daysBetween: " + daysBetween );
执行时…
start: 2008-04-26T00:00:00.000+02:00
stop: 2008-05-26T00:00:00.000+02:00
daysBetween: 30