7

我正在尝试计算两天之间的天数差异。出于某种原因,比较 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

4 回答 4

8

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

在 3 月 1 日和 4 月 1 日之间,由于夏令时开始,您有 30 个 24 小时日和 1 个 23 小时日。如果您将总毫秒数除以 24 x 60 x 60 x 1000,那么您将得到 30 加上 23/24。这被四舍五入到 30。

于 2014-02-03T09:33:01.717 回答
1

时区

David Wallace的正确答案解释说夏令时或其他异常会影响代码的结果。依赖默认时区(或完全忽略时区)会让你陷入这种麻烦。

使跨度包含-独占

此外,定义时间跨度的正确方法是让开头包含在内,结尾排除在外。所以如果你想要三月,你需要从第一天的第一刻到三月(4 月 1 日)之后第一天的第一刻。

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

这是我从其他答案中提取的图表:

时间线显示(>= 第 1 天开始)和(< 第 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 对象确实知道自己的时区,这与 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();

转储到控制台...</p>

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
于 2014-02-03T09:58:46.130 回答
0

I executed same code in my system it is giving me output as :

!!! Amount of days : 31

please check your code again.

于 2014-02-03T09:24:06.723 回答
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对此答案的评论。

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

于 2014-02-03T09:33:04.627 回答