7

I'm trying to calculate the difference between two days in amount of days. For some reason comparing 01-03-2013 and 01-04-2013 gives the result 30, as does comparing 01-03-2013 and 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

Why is this?

Morri
  • 571
  • 5
  • 20

4 Answers4

9

You will get those results if daylight savings started in your time zone on 31 March.

Between 1 March and 1 April, you have 30 24-hour days and one 23-hour day, because of the start of daylight savings. If you divide the total number of milliseconds by 24 x 60 x 60 x 1000, then you will get 30 plus 23/24. This gets rounded down to 30.

Dawood ibn Kareem
  • 77,785
  • 15
  • 98
  • 110
  • FYI… Daylight Saving Time (United States) 2013 began at 2:00 AM on Sunday, March 10 (so says The Google). – Basil Bourque Feb 03 '14 at 09:34
  • Right. That explains your result. OP is clearly not in USA. – Dawood ibn Kareem Feb 03 '14 at 09:34
  • This [list of DST changes](http://www.timeanddate.com/time/dst/2013a.html) does admit to being non-exhaustive, but interestingly notes that March 31st is a particularly popular switch date with nothing recorded on April 1st. – Duncan Jones Feb 03 '14 at 09:39
  • 1
    Yes, we have DST on 3-31-2013 , so this is causing the problem. TimeUnit.MILLISECONDS.toDays() casts the result instead of rounding it. – Morri Feb 03 '14 at 09:55
1

Time Zone

The correct answer by David Wallace explains that Daylight Saving Time or other anomalies affects the results of your code. Relying on default time zones (or outright ignoring time zones) will get you into this kind of trouble.

Make Span Inclusive-Exclusive

Also, the proper way to define a span of time is to make the beginning inclusive and the ending exclusive. So if you want the month of March, you need to go from first moment of first day to first moment of first day after March (April 1).

For lengthy discussion of this idea, see my other answers such as this one and this one.

Here's a diagram of mine lifted from other answers:

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

Joda-Time

The java.util.Date/Calendar classes bundled with Java are notoriously troublesome. Avoid them. Use either Joda-Time, or in Java 8, the new java.time.* package (inspired by Joda-Time).

The Joda-Time 2.3 library provides classes dedicated to spans of time: Period, Duration, and Interval. That library also has some handy static utility methods, such as Days.daysBetween.

Joda-Time's DateTime objects do know their own time zone, unlike java.util.Date/Calendar which seem to have a time zone but do not.

// 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();

Dump to console…

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 );

When run, notice:

  • The correct answer: 31
  • The difference in time zone offset because of Daylight Saving Time in France.
marchFirst: 2013-03-01T00:00:00.000+01:00
aprilFirst: 2013-04-01T00:00:00.000+02:00
days: 31
Community
  • 1
  • 1
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
0

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

!!! Amount of days : 31

please check your code again.

Gautam Savaliya
  • 1,403
  • 2
  • 20
  • 31
  • Yes, it depends on the time zone and when daylight savings kicks in. OP must have a 23-hour day in their timezone, when daylight savings started. The conversion to days divides by 24 x 60 x 60, and the 23 hours gets rounded down to zero. You are obviously in a different time zone from OP. – Dawood ibn Kareem Feb 03 '14 at 09:28
  • 1
    And I really ought to turn that comment into an answer of my own! – Dawood ibn Kareem Feb 03 '14 at 09:28
0

When I run this version of your code here in United States west coast time zone:

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 ) );

I get:

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

For explanation, see comment by David Wallace on this answer.

Daylight Saving Time (United States) 2013 began at 2:00 AM on Sunday, March 10.

Community
  • 1
  • 1
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154