¿Cuál es la diferencia entre Instant y LocalDateTime?

256

Yo sé eso:

  • Instant es más bien una representación de marca de tiempo "técnica" (nanosegundos) para la informática.
  • LocalDateTime es más bien una representación de fecha / reloj que incluye zonas horarias para humanos.

Aún al final, IMO puede tomarse como tipo para la mayoría de los casos de uso de aplicaciones. Como ejemplo: actualmente estoy ejecutando un trabajo por lotes en el que necesito calcular una próxima ejecución en función de las fechas y estoy luchando por encontrar un pros / contras entre estos dos tipos (aparte de la ventaja de precisión en nanosegundos de Instant y la parte de zona horaria) de LocalDateTime).

¿Puedes nombrar algunos ejemplos de aplicaciones, donde solo se deben usar Instant o LocalDateTime?

Editar: tenga cuidado con la documentación errónea de LocalDateTime sobre precisión y zona horaria

manuel aldana
fuente
Instantáneo es más elemental, envolviendo el estándar largo para el UTC. Para un cron como lote no es una elección tan lógica.
Joop Eggen
37
Definición incorrecta LocalDateTimeno no tiene una zona horaria!
Basil Bourque

Respuestas:

834

Tabla de todos los tipos de fecha y hora en Java, tanto modernos como heredados

tl; dr

Instanty LocalDateTimeson dos animales completamente diferentes: uno representa un momento, el otro no.

  • Instant representa un momento, un punto específico en la línea de tiempo.
  • LocalDateTimerepresenta una fecha y una hora del día. Pero sin una zona horaria o desplazamiento desde UTC, esta clase no puede representar un momento . Representa momentos potenciales a lo largo de un rango de aproximadamente 26 a 27 horas, el rango de todas las zonas horarias del mundo.

Presunción incorrecta

LocalDateTime es más bien una representación de fecha / reloj que incluye zonas horarias para humanos.

Su declaración es incorrecta: A noLocalDateTime tiene zona horaria . No tener zona horaria es el punto completo de esa clase.

Para citar el documento de esa clase:

Esta clase no almacena ni representa una zona horaria. En cambio, es una descripción de la fecha, como se usa para los cumpleaños, combinada con la hora local como se ve en un reloj de pared. No puede representar un instante en la línea de tiempo sin información adicional, como un desplazamiento o zona horaria.

Entonces Local…significa "sin zona, sin desplazamiento".

Instant

ingrese la descripción de la imagen aquí

Un Instantes un momento en la línea de tiempo en UTC , un recuento de nanosegundos desde la época del primer momento de 1970 UTC (básicamente, consulte el documento de la clase para obtener detalles). Dado que la mayor parte de la lógica de su negocio, el almacenamiento de datos y el intercambio de datos deben estar en UTC, esta es una clase útil para usar con frecuencia.

Instant instant = Instant.now() ;  // Capture the current moment in UTC.

OffsetDateTime

ingrese la descripción de la imagen aquí

La clase de OffsetDateTimeclase representa un momento como fecha y hora con un contexto de cierto número de horas-minutos-segundos delante o detrás de UTC. La cantidad de desplazamiento, la cantidad de horas-minutos-segundos, está representada por la ZoneOffsetclase.

Si el número de horas-minutos-segundos es cero, un OffsetDateTimerepresenta un momento en UTC igual que un Instant.

ZoneOffset

ingrese la descripción de la imagen aquí

La ZoneOffsetclase representa un desplazamiento desde UTC , una cantidad de horas-minutos-segundos delante de UTC o detrás de UTC.

A ZoneOffsetes simplemente una cantidad de horas-minutos-segundos, nada más. Una zona es mucho más, tiene un nombre y un historial de cambios para compensar. Por lo tanto, usar una zona siempre es preferible a usar un simple desplazamiento.

ZoneId

ingrese la descripción de la imagen aquí

Una zona horaria está representada por la ZoneIdclase.

Un nuevo día amanece más temprano en París que en Montreal , por ejemplo. Por lo tanto, debemos mover las manecillas del reloj para reflejar mejor el mediodía (cuando el Sol está directamente sobre la cabeza) para una región determinada. Cuanto más lejos esté hacia el este / oeste de la línea UTC en Europa occidental / África, mayor será el desplazamiento.

Una zona horaria es un conjunto de reglas para manejar los ajustes y las anomalías practicadas por una comunidad o región local. La anomalía más común es la locura demasiado popular conocida como horario de verano (DST) .

Una zona horaria tiene el historial de reglas pasadas, reglas presentes y reglas confirmadas para el futuro cercano.

Estas reglas cambian con más frecuencia de lo que cabría esperar. Asegúrese de mantener actualizadas las reglas de su biblioteca de fecha y hora, generalmente una copia de la base de datos 'tz' . Mantenerse actualizado es más fácil que nunca ahora en Java 8 con Oracle lanzando una herramienta de actualización de zona horaria .

Especificar un nombre de zona horaria correcta en el formato de Continent/Region, por ejemplo America/Montreal, Africa/Casablancao Pacific/Auckland. Nunca use el 2-4 abreviatura de letras tales como ESTo IST, ya que son no verdaderas zonas de tiempo, no estandarizados, y ni siquiera único (!).

Zona horaria = Offset + Reglas de ajustes

ZoneId z = ZoneId.of( Africa/Tunis ) ; 

ZonedDateTime

ingrese la descripción de la imagen aquí

Piense ZonedDateTimeconceptualmente como un Instantcon un asignado ZoneId.

ZonedDateTime = (Instant + ZoneId)

Para capturar el momento actual como se ve en el reloj de pared utilizado por las personas de una región en particular (una zona horaria):

ZonedDateTime zdt = ZonedDateTime.now( z ) ;  // Pass a `ZoneId` object such as `ZoneId.of( "Europe/Paris" )`. 

Casi todo el backend, la base de datos, la lógica de negocios, la persistencia de datos y el intercambio de datos deberían estar en UTC. Pero para la presentación a los usuarios, debe ajustarse a una zona horaria esperada por el usuario. Este es el propósito de la ZonedDateTimeclase y las clases de formateador utilizadas para generar representaciones de cadena de esos valores de fecha y hora.

ZonedDateTime zdt = instant.atZone( z ) ;
String output = zdt.toString() ;                 // Standard ISO 8601 format.

Puede generar texto en formato localizado utilizando DateTimeFormatter.

DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( Locale.CANADA_FRENCH ) ; 
String outputFormatted = zdt.format( f ) ;

30 mar avril 2019 à 23 h 22 min 55 s heure de l'Inde

LocalDate` LocalTime`LocalDateTime

Diagrama que muestra solo un calendario para un <code> LocalDate </code>.

Diagrama que muestra solo un reloj para un <code> LocalTime </code>.

Diagrama que muestra un calendario más un reloj para un <code> LocalDateTime </code>.

Las clases de fecha y hora "locales", LocalDateTime, LocalDate, LocalTime, son un tipo diferente de bicho. No están vinculados a ninguna localidad o zona horaria. No están vinculados a la línea de tiempo. No tienen un significado real hasta que los aplique a una localidad para encontrar un punto en la línea de tiempo.

La palabra "Local" en estos nombres de clase puede ser contra intuitiva para los no iniciados. La palabra significa cualquier localidad, o cada localidad, pero no una localidad particular.

Por lo tanto, para las aplicaciones comerciales, los tipos "locales" no se usan con frecuencia, ya que representan solo la idea general de una posible fecha u hora, no un momento específico en la línea de tiempo. Las aplicaciones comerciales tienden a preocuparse por el momento exacto en que llegó una factura, un producto enviado para el transporte, un empleado fue contratado o el taxi salió del garaje. Por lo tanto, los desarrolladores de aplicaciones empresariales usan Instanty ZonedDateTimeclasifican con mayor frecuencia.

Entonces, ¿cuándo usaríamos LocalDateTime? En tres situaciones: donde queremos aplicar una determinada fecha y hora del día en múltiples ubicaciones, donde estamos reservando citas o donde tenemos una zona horaria prevista pero indeterminada. Tenga en cuenta que ninguno de estos tres casos es un único punto específico en la línea de tiempo, ninguno de estos es un momento.

Una hora del día, múltiples momentos

A veces, queremos representar una determinada hora del día en una fecha determinada, pero queremos aplicarla en varias localidades en diferentes zonas horarias.

Por ejemplo, "La Navidad comienza a la medianoche del 25 de diciembre de 2015" es un LocalDateTime. Huelgas de medianoche en diferentes momentos en París que en Montreal, y de nuevo en Seattle y Auckland .

LocalDate ld = LocalDate.of( 2018 , Month.DECEMBER , 25 ) ;
LocalTime lt = LocalTime.MIN ;   // 00:00:00
LocalTime ldt = LocalDateTime.of( ld , lt ) ;  // Xmas morning anywhere. 

Otro ejemplo, "Acme Company tiene una política de que la hora del almuerzo comienza a las 12:30 PM en cada una de sus fábricas en todo el mundo" es a LocalTime. Para tener un significado real, debe aplicarlo a la línea de tiempo para calcular el momento de las 12:30 en la fábrica de Stuttgart o las 12:30 en la fábrica de Rabat o las 12:30 en la fábrica de Sydney .

Reserva de citas

Otra situación a utilizar LocalDateTimees para reservar eventos futuros (ej .: citas con el dentista). Estos nombramientos pueden estar lo suficientemente lejos en el futuro como para arriesgarse a que los políticos redefinan la zona horaria. Los políticos a menudo dan poca advertencia, o incluso ninguna advertencia. Si quiere decir "3 p. M. El próximo 23 de enero", independientemente de cómo jueguen los políticos con el reloj, entonces no puede registrar un momento: vería que las 3 p. M. Se convierten en 2 p. M. O 4 p. M. por ejemplo.

Para citas, almacene ay LocalDateTimea ZoneId, guardado por separado. Más tarde, al generar un horario, sobre la marcha determina un momento llamando LocalDateTime::atZone( ZoneId )para generar un ZonedDateTimeobjeto.

ZonedDateTime zdt = ldt.atZone( z ) ;  // Given a date, a time-of-day, and a time zone, determine a moment, a point on the timeline.

Si es necesario, puede ajustarse a UTC. Extraer un Instantde la ZonedDateTime.

Instant instant = zdt.toInstant() ;  // Adjust from some zone to UTC. Same moment, same point on the timeline, different wall-clock time.

Zona desconocida

Algunas personas pueden usar LocalDateTimeen una situación en la que se desconoce la zona horaria o el desplazamiento.

Considero este caso inapropiado e imprudente. Si se pretende una zona o desplazamiento pero no está determinado, tiene datos incorrectos. Eso sería como almacenar el precio de un producto sin conocer la moneda prevista. No es Buena idea.

Todos los tipos de fecha y hora

Para completar, aquí hay una tabla de todos los tipos posibles de fecha y hora, tanto modernos como heredados en Java, así como los definidos por el estándar SQL. Esto podría ayudar a colocar las clases Instant& LocalDateTimeen un contexto más amplio.

Tabla de todos los tipos de fecha y hora en Java (moderno y heredado), así como el estándar SQL.

Observe las elecciones extrañas realizadas por el equipo de Java al diseñar JDBC 4.2. Eligieron admitir todos los tiempos java.time ... excepto las dos clases más utilizadas: Instant& ZonedDateTime.

Pero no te preocupes. Podemos convertir fácilmente de un lado a otro.

La conversión Instant.

// Storing
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
myPreparedStatement.setObject(  , odt ) ;

// Retrieving
OffsetDateTime odt = myResultSet.getObject(  , OffsetDateTime.class ) ;
Instant instant = odt.toInstant() ;

La conversión ZonedDateTime.

// Storing
OffsetDateTime odt = zdt.toOffsetDateTime() ;
myPreparedStatement.setObject(  , odt ) ;

// Retrieving
OffsetDateTime odt = myResultSet.getObject(  , OffsetDateTime.class ) ;
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = odt.atZone( z ) ; 

Sobre java.time

El marco java.time está integrado en Java 8 y versiones posteriores. Estas clases suplantar la vieja problemáticos heredados clases de fecha y hora como java.util.Date, Calendar, y SimpleDateFormat.

El proyecto Joda-Time , ahora en modo de mantenimiento , aconseja la migración a las clases java.time .

Para obtener más información, consulte el Tutorial de Oracle . Y busque Stack Overflow para obtener muchos ejemplos y explicaciones. La especificación es JSR 310 .

Puede intercambiar objetos java.time directamente con su base de datos. Utilice un controlador JDBC compatible con JDBC 4.2 o posterior. No hay necesidad de cadenas, no hay necesidad de java.sql.*clases.

¿Dónde obtener las clases java.time?

Tabla de qué biblioteca java.time usar con qué versión de Java o Android

El proyecto ThreeTen-Extra extiende java.time con clases adicionales. Este proyecto es un campo de pruebas para posibles adiciones futuras a java.time. Usted puede encontrar algunas clases útiles aquí, como Interval, YearWeek, YearQuarter, y más .

Albahaca Bourque
fuente
40
Gran respuesta. Creo que cierta confusión (al menos la mía) proviene de la Localdenominación. Mi intuición de los Localmedios en relación con dónde estoy Y cuándo estoy (?!), Lo que me lleva a creer que en realidad sería lo que ZonedDateTimees.
mkobit
44
Sí, es confuso. Es por eso que java.time agregó ingeniosamente la palabra 'Zoned' al DateTimenombre de clase utilizado por su predecesor Joda-Time (productor ZonedDateTime), para enfatizar la diferencia con respecto a las clases "locales". Piense en el nombre "Local" como una abreviatura de "necesidad de aplicarse a alguna localidad en particular".
Basil Bourque
2
Prefijar con la palabra Localtambién puede haber sido una forma de diferenciarse del paquete java.util, aunque de alguna manera creo que podría haber una mejor elección de palabras.
vphilipnyc
2
@simonh Por el contrario ... Cuando ese nuevo empleado firme sus documentos de contratación definiendo sus beneficios, incluido el seguro de vida, y luego ese nuevo empleado salga a tomar un café solo para ser atropellado y asesinado por un camión, habrá muchas personas como gerentes de Recursos Humanos, agentes de seguros y abogados que van a querer saber el momento preciso en que entró en vigencia ese nuevo empleo.
Basil Bourque
2
@simonh Sí, hay casos en que la fecha y hora "local" es apropiada. Además de los mencionados en mi Respuesta, otro caso común en los negocios es para nombramientos que se harán más de un par de meses en el futuro, lo suficientemente lejos como para que los políticos puedan cambiar las reglas de la zona horaria, generalmente con poca advertencia. Los políticos con frecuencia realizan estos cambios, como cambiar las fechas al encender / apagar el horario de verano (DST) o permanecer permanentemente encendido / apagado DST.
Basil Bourque
20

Una diferencia principal es la Localparte de LocalDateTime. Si vives en Alemania y creas una LocalDateTimeinstancia y alguien más vive en EE. UU. Y crea otra instancia en el mismo momento (siempre que los relojes estén configurados correctamente), el valor de esos objetos sería realmente diferente. Esto no se aplica a Instant, que se calcula independientemente de la zona horaria.

LocalDateTimealmacena la fecha y la hora sin zona horaria, pero su valor inicial depende de la zona horaria. Instant's no es.

Además, LocalDateTimeproporciona métodos para manipular componentes de fecha como días, horas, meses. Un Instantno lo hace.

aparte de la ventaja de precisión en nanosegundos de Instant y la parte de zona horaria de LocalDateTime

Ambas clases tienen la misma precisión. LocalDateTimeNo almacena la zona horaria. Lea los javadocs a fondo, porque puede cometer un gran error con supuestos no válidos: Instant y LocalDateTime .

Dariusz
fuente
perdón por leer mal parte en zona + precisión. Perdón por repetir desde la publicación anterior: considerando una sola aplicación de zona horaria, ¿en qué casos de uso favorecería LocalDateTime o viceversa?
manuel aldana
1
Tomaría LocalDateTime cada vez que necesite fechas y / u horas. En horas, minutos, más o menos. Usaría Instant para medir los tiempos de ejecución, por ejemplo, o almacenar un campo interno de algo sucediendo en ese momento. Calculando las próximas carreras, como en su caso? LocalDateTime parece apropiado, pero es una opinión. Como dijiste, ambos se pueden usar.
Dariusz
¿Puedes dar más detalles LocalDateTime stores date and time without timezone, but it's initial value is timezone dependent? ¿Cuál es el valor inicial y cómo depende de la zona horaria? Gracias.
Max
12

Estás equivocado LocalDateTime: no almacena ninguna información de zona horaria y tiene una precisión de nanosegundos. Citando el Javadoc (énfasis mío):

Una fecha y hora sin zona horaria en el sistema de calendario ISO-8601 , como 2007-12-03T10: 15: 30.

LocalDateTime es un objeto de fecha y hora inmutable que representa una fecha y hora, a menudo vista como año-mes-día-hora-minuto-segundo. También se puede acceder a otros campos de fecha y hora, como el día del año, el día de la semana y la semana del año. El tiempo se representa con una precisión de nanosegundos . Por ejemplo, el valor "2 de octubre de 2007 a las 13: 45.30.123456789" se puede almacenar en un LocalDateTime.

La diferencia entre los dos es que Instantrepresenta un desplazamiento de la época (01-01-1970) y, como tal, representa un instante particular en la línea de tiempo. Dos Instantobjetos creados en el mismo momento en dos lugares diferentes de la Tierra tendrán exactamente el mismo valor.

Tunaki
fuente
Considerando una sola aplicación de zona horaria, ¿en qué casos de uso preferiría LocalDateTime o viceversa?
manuel aldana
3
@manuelaldana Es más una cuestión de gustos. Prefiero LocalDateTime para cualquier cosa relacionada con el usuario (cumpleaños ...) e Instant para cualquier cosa relacionada con la máquina (tiempo de ejecución ...).
Tunaki
2
@manuelaldana Una aplicación de zona horaria única es rara, si no inexistente. Es posible que ignore las zonas horarias para una pequeña aplicación que creó para su club de música barroca local. Pero tan pronto como necesite publicar un evento para las personas que viajan (y cruzan zonas horarias) querrán que los datos estén vinculados a una zona horaria para que su aplicación de calendario pueda ajustarse según sea necesario. Le sugiero que aprenda a trabajar correctamente con las zonas horarias en todas sus aplicaciones.
Basil Bourque
@Tunaki El uso de la palabra 'desplazamiento' en el último párrafo es una distracción. Esa palabra tiene un cierto significado en el trabajo de fecha y hora, por lo que su uso aquí en este contexto podría ser inútil.
Basil Bourque
0

Instant corresponde al tiempo en el meridiano principal (Greenwich).

Considerando que en LocalDateTimerelación con la configuración de zona horaria del sistema operativo, y

no puede representar un instante sin información adicional, como un desplazamiento o zona horaria.

usuario2418306
fuente
2
Instant está basado en UTC no GMT.
Torsten Ojaperv