Подтвердить что ты не робот

Что произошло между 28 марта и 29 марта 1976 года с помощью java.util.GregorianCalendar?

Пытаясь использовать GregorianCalendar, я застрял в сингулярности, вычисляя количество дней с той или иной даты. В интерпретаторе scala я ввел:

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

Я не знаю, имеет значение тот факт, что 1976 год является високосным годом, но дни1 и дни2 должны были быть разделены 1. Это единственный момент в истории с 1970 года, когда эта особенность происходит.

Желая узнать, что происходит, я вычисляю разницу между двумя датами, которые были упомянуты ранее, и это дает мне ровно 23 часа разницы! Что случилось в этот день? Википедия, по-видимому, ничего не говорит об этом.

И что еще более важно, как вычислить реальное количество дней с определенной даты?

4b9b3361

Ответ 1

Если опция разделения с плавающей точкой недоступна, лучшим ответом, о котором я могу думать, является добавление одного часа (1000 * 3600) при вычислении разницы между двумя днями:

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

Он должен работать на каждую дату, так как вы больше не страдаете от прыжков.

Ответ 2

Проблема

Дневной свет составляет всего 23 часа.

И в соответствии с этим 28 марта 1976 года был дневной день, по крайней мере, в Париже. Час между 1:00 и 2:00 в тот день просто не существовал.

Хотя это проблема локали, поскольку на моем компьютере я правильно понимаю:

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

Я не в Париже и нигде, где в тот день было изменение времени; время изменилось 25 апреля 1976 года, где я. Таким образом, я получаю поведение "пропущенного дня" в эту дату:

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

Эрвин указывает в комментариях, что вероятная причина, по которой вы заметили неверную разницу в дате, заключается в том, что все другие дневные сберегательные дни компенсируются 25-часовыми днями, которые также происходят в те годы, когда дневной свет исправляется.

Решение

Используйте лучшую библиотеку для обработки даты. Библиотека joda-time делает это правильно (а также является лучшей средой даты и времени):

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 указал, что я думаю: этот день - день "летнего времени". Поскольку этот день длится всего 23 часа, эвклидовое деление на день равно 0.

Фактически, использование объектов GregorianCalendar использует только дату в миллисекундах, поэтому деление на один день как целое только сокращает результат.

Вместо евклидова (целочисленного) деления попытайтесь выполнить разделение с плавающей точкой, а затем округлите результат.