Saltar al contenido

LocalDateTime a ZonedDateTime

Recabamos por el mundo online y así de esta forma traerte la respuesta a tu duda, si tienes alguna pregunta puedes dejar la inquietud y te respondemos con gusto.

Solución:

Postgres no tiene un tipo de datos como TIMESTAMP. Postgres tiene dos tipos de fecha y hora del día: TIMESTAMP WITH TIME ZONE y TIMESTAMP WITHOUT TIME ZONE. Estos tipos tienen un comportamiento muy diferente con respecto a la información de la zona horaria.

  • los WITH escribe usa cualquier compensación o información de zona horaria para ajustar la fecha y hora a UTC, luego elimina esa compensación o zona horaria; Postgres nunca guarda la información de compensación / zona.
  • Este tipo representa un momento, un punto específico en la línea de tiempo.
  • los WITHOUT escribe ignora cualquier compensación o información de zona que pueda estar presente.
  • Este tipo lo hace no representar un momento. Representa una vaga idea de potencial momentos a lo largo de un rango de aproximadamente 26-27 horas (el rango de zonas horarias alrededor del mundo).

Prácticamente siempre quieres el WITH tipo, como lo explica aquí el experto David E. Wheeler. los WITHOUT solo tiene sentido cuando tienes la vaga idea de una fecha y hora en lugar de un punto fijo en la línea de tiempo. Por ejemplo, “La Navidad de este año comienza en 2016-12-25T00: 00: 00” se almacenaría en el WITHOUT como se aplica a alguna zona horaria, que aún no se ha aplicado a una sola zona horaria para obtener un momento real en la línea de tiempo. Si los elfos de Santa estuvieran rastreando la hora de inicio de Eugene Oregon US, entonces usarían el WITH tipo y una entrada que incluye un desplazamiento o zona horaria como 2016-12-25T00:00:00-08:00 que se guarda en Postgres como 2016-12-25T08:00.00Z (donde el Z significa zulú o UTC).

El equivalente de Postgres ‘ TIMESTAMP WITHOUT TIME ZONE en java.time es java.time.LocalDateTime. Como su intención era trabajar en UTC (algo bueno), debería no estar usando LocalDateTime (una cosa mala). Ese puede ser el principal punto de confusión y problemas para usted. Sigues pensando en usar LocalDateTime o ZonedDateTime pero no deberías usar ninguno; en su lugar deberías estar usando Instant (se discute más adelante).

También me pregunto si debido a que voy de LocalDateTime a ZonedDateTime y viceversa, podría estar perdiendo información sobre la zona horaria.

De hecho son. Todo el punto para LocalDateTime Es para perder información de zona horaria. Por eso, rara vez usamos esta clase en la mayoría de las aplicaciones. De nuevo, el ejemplo de la Navidad. O otro ejemplo, “Política de la empresa: todas nuestras fábricas en todo el mundo almuerzan a las 12:30 PM”. Eso sería LocalTime, y para una fecha en particular, LocalDateTime. Pero eso no tiene un significado real, no es un punto real en la línea de tiempo, hasta que aplica una zona horaria para obtener una ZonedDateTime. Esa pausa para el almuerzo será en diferentes puntos de la línea de tiempo en la fábrica de Delhi que en la fábrica de Düsseldorf y nuevamente diferente en la fábrica de Detroit.

La palabra “Local” en LocalDateTime puede ser contrario a la intuición, ya que significa no particular localidad. Cuando lea “Local” en el nombre de una clase, piense “Ni un momento … no en la línea de tiempo … solo una idea borrosa sobre una especie de fecha y hora”.

Sus servidores casi siempre deben estar configurados en UTC en la zona horaria de su sistema operativo. Pero su programación nunca debería depender de esta externalidad, ya que es demasiado fácil para un administrador de sistemas cambiarla o para cualquier otra aplicación Java cambiar la zona horaria predeterminada actual dentro de la JVM. Por lo tanto, siempre especifique su zona horaria deseada / esperada. (Lo mismo ocurre con Locale, por cierto.)

Resultado:

  • Estás trabajando demasiado duro.
  • Los programadores / administradores de sistemas deben aprender a “pensar globalmente, presentar localmente”.

Durante el día de trabajo mientras usa su casco geek, piense en UTC. Solo al final del día, cuando cambie a la de su laico, debe volver a pensar en la hora local de su ciudad.

Su lógica empresarial debe centrarse en UTC. El almacenamiento de su base de datos, la lógica empresarial, el intercambio de datos, la serialización, el registro y su propio pensamiento deben realizarse en la zona horaria UTC (y en formato de 24 horas, por cierto). Al presentar datos a los usuarios, solo entonces aplique una zona horaria en particular. Piense en las fechas y horas divididas en zonas como algo externo, no como una parte funcional de los componentes internos de su aplicación.

En el lado de Java, use java.time.Instant (un momento en la línea de tiempo en UTC) en gran parte de su lógica empresarial.

Instant now = Instant.now();

Con suerte, los controladores JDBC eventualmente se actualizarán para lidiar con tipos java.time como Instant directamente. Hasta entonces debemos usar tipos java.sql. La antigua clase java.sql tiene nuevos métodos para la conversión a / desde java.time.

java.sql.TimeStamp ts = java.sql.TimeStamp.valueOf( instant );

Ahora pasa eso java.sql.TimeStamp objeto a través de setTimestamp en un PreparedStatement para ser guardado en una columna definida como TIMESTAMP WITH TIME ZONE en Postgres.

Para ir en la otra dirección:

Instant instant = ts.toInstant();

Así que es fácil pasar de Instant para java.sql.Timestamp para TIMESTAMP WITH TIME ZONE, todo en UTC. No hay zonas horarias involucradas. La zona horaria predeterminada actual de su sistema operativo de servidor, su JVM y sus clientes es irrelevante.

Para presentar al usuario, aplique una zona horaria. Utilice nombres de zona horaria adecuados, nunca códigos de 3 a 4 letras como EST o IST.

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

Puede adaptarse a una zona diferente según sea necesario.

ZonedDateTime zdtKolkata = zdt.withZoneSameInstant( ZoneId.of( "Asia/Kolkata" ) );

Para volver a un Instant, un momento en la línea de tiempo en UTC, puede extraer de la ZonedDateTime.

Instant instant = zdt.toInstant();

En ningún lugar usamos LocalDateTime.

Si obtiene un dato sin ningún desplazamiento de UTC o zona horaria, como 2016-04-04T08:00, esos datos son completamente inútiles para usted (asumiendo que no estamos hablando de los escenarios del tipo Almuerzo de empresa o Navidad discutidos anteriormente). Una fecha y hora sin información de compensación / zona es como una cantidad monetaria sin indicar la moneda: 142.70 o incluso $142.70 — inútil. Pero USD 142.70, o CAD 142.70, o MXN 142.70… Esos son útiles.

Si consigues eso 2016-04-04T08:00 valor, y tu eres absolutamente cierto del contexto de compensación / zona previsto, entonces:

  1. Analizar eso string como un LocalDateTime.
  2. Aplicar un desplazamiento de UTC para obtener un OffsetDateTimeo (mejor) aplique una zona horaria para obtener una ZonedDateTime.

Como este código.

LocalDateTime ldt = LocalDateTime.parse( "2016-04-04T08:00" );
ZoneId zoneId = ZoneId.of( "Asia/Kolkata" ); // Or "America/Montreal" etc.
ZonedDateTime zdt = ldt.atZone( zoneId ); // Or atOffset( myZoneOffset ) if only an offset is known rather than a full time zone.

Su pregunta es realmente un duplicado de muchas otras. Estos temas se han discutido muchas veces en otras Preguntas y Respuestas. Le insto a que busque y estudie Stack Overflow para obtener más información sobre este tema.

JDBC 4.2

A partir de JDBC 4.2 podemos intercambiar directamente java.time objetos con la base de datos. No es necesario usarlo nunca java.sql.Timestamp de nuevo, ni sus clases relacionadas.

Almacenar, usar OffsetDateTime como se define en la especificación JDBC.

myPreparedStatement.setObject( … , instant.atOffset( ZoneOffset.UTC ) ) ;  // The JDBC spec requires support for `OffsetDateTime`. 

… o posiblemente usar Instant directamente, si es compatible con su controlador JDBC.

myPreparedStatement.setObject( … , instant ) ;  // Your JDBC driver may or may not support `Instant` directly, as it is not required by the JDBC spec. 

Recuperando.

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;

Tabla de tipos de fecha y hora en Java (tanto heredado como moderno) y en SQL estándar


Sobre java.time

los java.time framework está integrado en Java 8 y versiones posteriores. Estas clases suplantan a las antiguas y problemáticas clases de fecha y hora heredadas, como java.util.Date, CalendarY SimpleDateFormat.

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.

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

Puedes intercambiar java.time objetos directamente con su base de datos. Utilice un controlador JDBC compatible con JDBC 4.2 o posterior. Sin necesidad de cuerdas, sin necesidad de java.sql.* clases. Compatibilidad con Hibernate 5 y JPA 2.2 java.time.

¿Dónde obtener las clases java.time?

  • Java SE 8, Java SE 9, Java SE 10, Java SE 11y posterior: parte de la API estándar de Java con una implementación integrada.
    • Java 9 trajo algunas características y correcciones menores.
  • Java SE 6 y Java SE 7
    • La mayoría de java.time la funcionalidad está respaldada a Java 6 y 7 en ThreeTen-Backport.
  • Androide
    • Versiones posteriores de implementaciones de paquetes de Android (26+) del java.time clases.
    • Para Android anterior (<26), un proceso conocido como API desugaring trae un subconjunto del java.time funcionalidad no incorporada originalmente en Android.
      • Si el desugaring no ofrece lo que necesita, el ThreeTenABP el proyecto se adapta ThreeTen-Backport (mencionado anteriormente) a Android. Ver Cómo usar ThreeTenABP….

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

TLDR:

Para convertir de LocalDateTime a ZonedDateTime el siguiente código. Puedes usar .atZone( zoneId ), una lista completa de zoneID se encuentra en la columna TZ database name en Wikipedia.

LocalDateTime localDateTime = LocalDateTime.parse( "2016-04-04T08:00" );
ZoneId zoneId = ZoneId.of( "UTC" ); // Or "Asia/Kolkata" etc.
ZonedDateTime zdt = localDateTime.atZone( zoneId );

Sección de Reseñas y Valoraciones

Si posees algún reparo o forma de reaccionar nuestro escrito te recordamos escribir una explicación y con deseo lo observaremos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *