Java TimeUnit.MILLISECONDS.toDays()给出了错误的结果

时间:2014-02-03 09:12:44

标签: java date calendar timeunit

我正在尝试计算两天天数之间的差异。出于某种原因,比较01-03-2013和01-04-2013给出结果30,比较01-03-2013和31-03-2013

Calendar cal = Calendar.getInstance();
cal.clear();

cal.set(2013, Calendar.MARCH, 1);
Date start = cal.getTime();

cal.set(2013, Calendar.APRIL, 1);
Date end = cal.getTime();

long days = TimeUnit.MILLISECONDS.toDays(end.getTime() - start.getTime());
System.out.println("!!! Amount of days : " + String.valueOf(days));

>> 30

cal.set(2013, Calendar.MARCH, 1);
start = cal.getTime();

cal.set(2013, Calendar.MARCH, 31);
end = cal.getTime();

days = TimeUnit.MILLISECONDS.toDays(end.getTime() - start.getTime());
System.out.println("!!! Amount of days : " + String.valueOf(days));

>> 30

为什么会这样?

4 个答案:

答案 0 :(得分:6)

如果在3月31日的时区开始夏令时,您将获得这些结果。

在3月1日至4月1日期间,由于夏令时的开始,您有30个24小时工作日和一个23个工作小时工作日。如果您将总毫秒数除以24 x 60 x 60 x 1000,那么您将获得30加23/24。这会缩小到30。

答案 1 :(得分:1)

时区

correct answer by David Wallace解释了Daylight Saving Time或其他异常会影响代码的结果。依靠默认时区(或完全忽略时区)会让您遇到这种麻烦。

使跨度独占

此外,定义时间跨度的正确方法是使开头包含,而将结尾排除。因此,如果您想要三月份,您需要从第一天的第一天开始到三月(四月一日)之后的第一天

有关此想法的冗长讨论,请参阅我的其他答案,例如this onethis one

这是我从其他答案中解脱出来的图表:

Timeline showing ( >= start of day 1 ) and ( < start of day 8 )

约达时间

与Java捆绑在一起的java.util.Date/Calendar类非常麻烦。避免他们。使用Joda-Time或Java 8,新的java.time。*包(受Joda-Time启发)。

Joda-Time 2.3库提供专用于时间跨度的类:Period,Duration和Interval。该库还有一些方便的静态实用方法,例如Days.daysBetween

Joda-Time的DateTime对象确实知道自己的time zone,不像java.util.Date/Calendar似乎有时区但没有。

// Specify a timezone rather than rely on default.
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" );

DateTime marchFirst = new DateTime( 2013, DateTimeConstants.MARCH, 1, 0, 0, 0, timeZone );
DateTime aprilFirst = new DateTime( 2013, DateTimeConstants.APRIL, 1, 0, 0, 0, timeZone );

int days = Days.daysBetween( marchFirst, aprilFirst).getDays();

转储到控制台...

System.out.println( "marchFirst: " + marchFirst );
System.out.println( "aprilFirst: " + aprilFirst ); // Note the change in time zone offset in the output.
System.out.println( "days: " + days );

运行时,请注意:

marchFirst: 2013-03-01T00:00:00.000+01:00
aprilFirst: 2013-04-01T00:00:00.000+02:00
days: 31

答案 2 :(得分:0)

我在我的系统中执行相同的代码,它输出为:

!!! Amount of days : 31

请再次检查您的代码。

答案 3 :(得分:0)

当我在美国西海岸时区运行此版本的代码时:

java.util.Calendar cal = java.util.Calendar.getInstance();
cal.clear();

cal.set( 2013, java.util.Calendar.MARCH, 1 );
java.util.Date start = cal.getTime();

cal.set( 2013, java.util.Calendar.APRIL, 1 );
java.util.Date end = cal.getTime();

long days = java.util.concurrent.TimeUnit.MILLISECONDS.toDays( end.getTime() - start.getTime() );
System.out.println( "!!! Amount of days : " + String.valueOf( days ) );

cal.set( 2013, java.util.Calendar.MARCH, 1 );
start = cal.getTime();

cal.set( 2013, java.util.Calendar.MARCH, 31 );
end = cal.getTime();

days = java.util.concurrent.TimeUnit.MILLISECONDS.toDays( end.getTime() - start.getTime() );
System.out.println( "!!! Amount of days : " + String.valueOf( days ) );

我明白了:

!!! Amount of days : 30
!!! Amount of days : 29

有关解释,请参阅David Wallace对this answer的评论。

夏令时(美国)2013年3月10日星期日凌晨2:00开始。