La conversión de java.util.Date (01.01.0001) a java.time.LocalDate devuelve 29.12.0000
Quiero analizar java.util.Date
y java.time.LocalDate
encontré este código cuando busqué el problema:
Date date = new SimpleDateFormat("dd.MM.yyyy").parse("01.01.0001");
date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
si tengo la 01.01.0001
fecha de inicio, tengo problemas:
date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
==> (java.time.LocalDate) 0000-12-29
29.12.0000
y 01.01.0001
no son lo mismo.
- ¿Por qué el resultado real es diferente del esperado?
- ¿Qué puedo hacer si también quiero recibir el
LocalDate
con el valor01.01.0001
?
Información sobre la zona horaria:
ZoneId.systemDefault()
==> (java.time.ZoneRegion) Europa/Berlín
- Creo que el problema es este paso:
date.toInstant()
- No creo que sea (sólo) un problema de zona horaria. Si lo pruebo con un año diferente. Por ejemplo 1901, que termina el 31.12.1900.
Date date0001 = new SimpleDateFormat("dd.MM.yyyy").parse("01.01.0001");
System.out.println(date0001.toInstant());
==> 0000-12-29T23:00:00Z
Date date1901 = new SimpleDateFormat("dd.MM.yyyy").parse("01.01.1901");
System.out.println(date1901.toInstant());
==> 1900-12-31T23:00:00Z
java.tiempo
Comprenda que Java viene con dos marcos de fecha y hora diferentes.
- Uno tiene terribles defectos y ahora es un legado .
- El otro es líder en la industria, definido en JSR 310, y todas las clases se encuentran en los
java.time.*
paquetes.
Vivamos el primer momento de tu año 1.
Instant yearOneStartInUtc = Instant.parse ( "0001-01-01T00:00:00Z" );
añoOneStartInUtc.toString() = 0001-01-01T00:00:00Z
El Z
final se pronuncia "zulú" y representa un desplazamiento de cero horas, minutos y segundos con respecto al meridiano temporal de UTC.
Podemos convertir libremente entre los marcos heredados y modernos llamando a nuevos métodos agregados a las clases antiguas.
java.util.Date judStart = java.util.Date.from ( yearOneStartInUtc );
judStart.toString() = domingo 02 de enero 16:00:00 PST 1
Evite clases heredadas de fecha y hora
Note que el java.util.Date#toString
método nos miente a nosotros. Si bien java.util.Date
representa un momento como se ve en UTC (un desplazamiento de cero), su toString
método aplica dinámicamente la zona horaria predeterminada actual de la JVM mientras genera su resultado de texto. Esta es una de las muchas razones para evitar esta clase heredada, así como Calendar
, SimpleDateFormat
etc.
Ahora podemos ver el resto de su código.
Ajuste entre zonas
Aplicó una zona horaria a una Instant
para ajustarla desde UTC. Se olvidó de decirnos cuál es esa zona horaria. Entonces, elijamos arbitrariamente la zona horaria America/Edmonton
. Esta zona horaria utiliza un desfase de varias horas detrás de UTC.
ZoneId zoneEdmonton = ZoneId.of ( "America/Edmonton" );
ZonedDateTime zdtYearOneStart = yearOneStartInUtc.atZone ( zoneEdmonton );
zdtYearOneStart.toString() = 0000-12-31T16:26:08-07:33:52[América/Edmonton]
Observe que la fecha difiere de la entrada, 0000-12-31 versus 0001-01-01. La hora también difiere, 16:26:08-07:33:52 versus 00:00:00. Y ahí radica nuestra explicación.
Imaginemos que en ese mismo momento, cuando la fecha y el año cambiaron, Alice se encontraba en el futuro emplazamiento del Observatorio Real de Greenwich . Observó la hora actual de 00:00:00 el día de Año Nuevo. Pero para Bob bebiendo nog en Edmonton, Alberta, Canadá, ese mismo momento simultáneo fue la víspera de Año Nuevo , no el día de Año Nuevo . Y cuando Bob miraba el reloj de su pared, veía la hora varias horas antes de la medianoche. Alice estaba en el “año próximo” 0001, mientras que Bob estaba simultáneamente en el “año pasado” 0000.
👉🏽 Para un momento dado, la hora y la fecha varían en todo el mundo según la zona horaria.
Entonces, la diferencia entre las fechas del 1 de enero y el 31 de diciembre tiene sentido. Sin embargo, su resultado del 29 de diciembre no tiene sentido. No ha proporcionado un MCVE , por lo que sospecho que ha cometido un error.
29.12.0000 y 01.01.0001 no son lo mismo.
En efecto. Lo que debemos entender es lo siguiente: cada vez que conviertes una hora o una fecha a otra zona horaria, si las dos zonas horarias son diferentes, entonces la fecha resultante podría terminar siendo diferente también.
Tienes dos conversiones de fecha:
atZone()
toLocalDate()
atZone regresa ZonedDateTime
. toLocalDate
convierte su fecha en otra fecha de zona horaria: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html .
Hay más de 24 zonas horarias.
Entonces, si realiza dos conversiones de esta manera, es muy posible que las dos conversiones en total resten al menos 24 horas y, por lo tanto, resulten en dos diferencias de fecha.
Me sorprende ver que en realidad tienes una diferencia de 3 días. Deberá dividir su código y ver dónde ocurren realmente los cambios de datos. Podrían ser diferencias de zona horaria como las que describí. O podrían haber algunos errores en su código o en la biblioteca heredada. Quizás tengas más conversiones.
Una forma muy "sencilla" de retroceder en el tiempo de esta manera para convertir fechas reales a zonas horarias y olvidar las horas. Luego, si los cambios de zona horaria tienen compensaciones de zona horaria decrecientes, se restarán días repetidamente.