La conversión de java.util.Date (01.01.0001) a java.time.LocalDate devuelve 29.12.0000

Resuelto DYL asked hace 1 año • 0 respuestas

Quiero analizar java.util.Datey 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.0001fecha de inicio, tengo problemas:

date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

==> (java.time.LocalDate) 0000-12-29

29.12.0000y 01.01.0001no son lo mismo.

  1. ¿Por qué el resultado real es diferente del esperado?
  2. ¿Qué puedo hacer si también quiero recibir el LocalDatecon el valor 01.01.0001?

Información sobre la zona horaria:

ZoneId.systemDefault()

==> (java.time.ZoneRegion) Europa/Berlín

  1. Creo que el problema es este paso:date.toInstant()
  2. 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

DYL avatar Nov 06 '23 18:11 DYL
Aceptado

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 Zfinal 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#toStringmétodo nos miente a nosotros. Si bien java.util.Daterepresenta un momento como se ve en UTC (un desplazamiento de cero), su toStringmé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, SimpleDateFormatetc.

Ahora podemos ver el resto de su código.

Ajuste entre zonas

Aplicó una zona horaria a una Instantpara 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.

Basil Bourque avatar Nov 06 '2023 20:11 Basil Bourque

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. toLocalDateconvierte 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.

ingrese la descripción de la imagen aquí

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.

Lajos Arpad avatar Nov 07 '2023 10:11 Lajos Arpad