问题
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 ?
回答1:
If the option of a float division is not available, the best answer I can think of is to add one hour (1000*3600) while computing a difference between two days:
scala> (dateToday - (new GregorianCalendar(1976, Calendar.MARCH, 28).getTimeInMillis()) + 1000*3600) / (1000 * 3600 * 24)
days1: Long = 13204
scala> (dateToday - (new GregorianCalendar(1976, Calendar.MARCH, 29).getTimeInMillis()) + 1000*3600) / (1000 * 3600 * 24)
days1: Long = 13203
It should work for every date, as you do not suffer from leap hours anymore.
回答2:
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
回答3:
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.
来源:https://stackoverflow.com/questions/10698470/what-happened-between-march-28th-and-march-29th-1976-with-the-java-util-gregori