milisegundos - java timestamp to date
¿Qué sucedió entre el 28 de marzo y el 29 de marzo de 1976 con el java.util.GregorianCalendar? (3)
Tratando de usar el calendario de Gregorian, me quedé atascado en una singularidad al calcular el número de días desde una fecha en particular. En el intérprete de scala, ingresé
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
No sé si el hecho de que 1976 sea un año bisiesto es importante, pero los días 1 y 2 deberían haberse separado por 1. Este es el único momento en la historia desde 1970 en que ocurre esta singularidad.
Queriendo saber qué está pasando, calculo la diferencia entre las dos fechas mencionadas anteriormente, ¡y me da exactamente 23 horas de diferencia! ¿Qué pasó en esa fecha? Wikipedia aparentemente no dice nada al respecto.
Y aún más importante, ¿cómo calcular el número real de días desde una fecha en particular?
El problema
Los días de ahorro de luz diurna solo duran 23 horas.
Y de acuerdo con this 28 de marzo de 1976, fue un día de ahorro de energía en al menos París. La hora entre la 1 am y las 2 am en ese día simplemente no existía.
Aunque debe ser un problema de configuración regional, ya que en mi computadora lo hago bien:
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
No estoy en París ni en ningún otro lugar que haya cambiado de horario ese día; La hora cambió el 25 de abril de 1976 donde estoy. Entonces obtengo el comportamiento de "día omitido" en esa fecha:
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 señala en los comentarios que la razón probable por la que usted solo nota la diferencia de fecha incorrecta aquí es que todos los demás días de ahorro de luz natural se compensan con los días de 25 horas que también ocurren en esos años, cuando se corrige el día de ahorro de energía.
La solución
Utilice una mejor biblioteca para el procesamiento de la fecha. La biblioteca de joda-time hace correctamente (además de ser un mejor marco de fecha / hora en general):
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
Si la opción de una división flotante no está disponible, la mejor respuesta que se me ocurre es agregar una hora (1000 * 3600) al calcular una diferencia entre dos días:
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
Debería funcionar para todas las fechas, ya que ya no sufres más horas de salto.
dhg señaló lo que pienso: este día es un día de "horario de verano". Como este día solo dura 23 horas, la división euclidiana por día equivale a 0.
De hecho, el uso de objetos GregorianCalendar solo usa una fecha como milisegundos, por lo que dividir por un día como un número entero solo trunca un resultado.
En lugar de una división euclidiana (entero), intente hacer una división flotante, luego redondee el resultado.