Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What happened between March 28th and March 29th, 1976 with the java.util.GregorianCalendar?

Trying to use the GregorianCalendar, I got stuck on a singularity while computing the number of days since a particular date. In the scala interpreter, I entered :

scala>import java.util.GregorianCalendar
scala>import java.util.Calendar
scala>val dateToday = new GregorianCalendar(2012,Calendar.MAY,22).getTimeInMillis()
dateToday: Long = 1337637600000
scala>val days1 = (dateToday - (new GregorianCalendar(1976,Calendar.MARCH,28).getTimeInMillis())) / (1000*3600*24)
days1: Long = 13203
scala>val days2 = (dateToday - (new GregorianCalendar(1976,Calendar.MARCH,29).getTimeInMillis())) / (1000*3600*24)
days2: Long = 13203

I don't know if the fact that 1976 is a leap year matters, but days1 and days2 should have been separated by 1. This is the only moment in history since 1970 that this singularity happens.

Wanting to know what is going on, I compute the difference between the two dates previously mentionned, and it gives me only exactly 23 hours of difference ! What happened on that date ? Wikipedia apparently says nothing about it.

And even more important, how to compute the real number of days since a particular date ?

like image 298
Mikaël Mayer Avatar asked May 22 '12 08:05

Mikaël Mayer


2 Answers

The Problem

Daylight savings days are only 23 hours long.

And according to this March 28th, 1976 was a daylight savings day in at least Paris. The hour between 1am and 2am on that day simply did not exist.

Though it must be a Locale issue since on my computer I get it right:

scala> val days1 = (dateToday - (new GregorianCalendar(1976, Calendar.MARCH, 28).getTimeInMillis())) / (1000 * 3600 * 24)
days1: Long = 13203

scala> val days2 = (dateToday - (new GregorianCalendar(1976, Calendar.MARCH, 29).getTimeInMillis())) / (1000 * 3600 * 24)
days2: Long = 13202

I'm not in Paris or anywhere else that had a time change on that day; the time changed on April 25, 1976 where I am. So I get the "skipped day" behavior on that date:

scala> val days3 = (dateToday - (new GregorianCalendar(1976, Calendar.APRIL, 25).getTimeInMillis())) / (1000 * 3600 * 24)
days3: Long = 13175

scala> val days4 = (dateToday - (new GregorianCalendar(1976, Calendar.APRIL, 26).getTimeInMillis())) / (1000 * 3600 * 24)
days4: Long = 13175

Erwin points on in the comments that the likely reason your only noticing the incorrect date difference here is that all of the other daylight savings days are offset by the 25-hour days that also happen in those years, when the daylight savings day is corrected.

The Solution

Use a better library for date processing. The joda-time library does it correctly (as well as being a better date/time framework overall):

import org.joda.time.Days
import org.joda.time.DateTimeConstants
import org.joda.time.DateMidnight

val d1 = new DateMidnight(1976, DateTimeConstants.APRIL, 25)
val d2 = new DateMidnight(1976, DateTimeConstants.APRIL, 26)
val x = Days.daysBetween(d1, d2).getDays()
println(x) // 1
like image 156
dhg Avatar answered Nov 17 '22 17:11

dhg


dhg pointed out what I think: This day is a "daylight saving time" day. As this day is only 23h long, euclidian division by a day equals 0.

In fact, using GregorianCalendar objects is only using a date as milliseconds, so dividing by one day as an integer does only truncate a result.

Instead of an euclidian (integer) division, try to do a float division, then round the result.

like image 4
Arglanir Avatar answered Nov 17 '22 16:11

Arglanir