sql >> Base de Datos >  >> RDS >> PostgreSQL

¿Cuál es la forma más recomendada de almacenar tiempo en PostgreSQL usando Java?

Cualquier estrategia para almacenar datos de fecha y hora en PostgreSQL debe, en mi opinión, basarse en estos dos puntos:

  • Su solución nunca depende de la configuración de la zona horaria del servidor o del cliente.
  • Actualmente, PostgreSQL (como la mayoría de las bases de datos) no tiene un tipo de datos para almacenar un completo fecha y hora con zona horaria. Entonces, debes decidir entre un Instant o un LocalDateTime tipo de datos.

Mi receta sigue.

Si desea grabar el instante físico en el momento en que ocurrió un evento en particular (una verdadera "marca de tiempo " , típicamente algún evento de creación/modificación/eliminación), luego use:

  • Java:Instant (Java 8 o Jodatime).
  • JDBC:java.sql.Timestamp
  • PostgreSQL:TIMESTAMP WITH TIMEZONE (TIMESTAMPTZ )

(No permita que los tipos de datos peculiares de PostgreSQL WITH TIMEZONE /WITHOUT TIMEZONE confundirte:ninguno de ellos almacena una zona horaria)

Algún código repetitivo:lo siguiente asume que ps es una PreparedStatement , rs un ResultSet y tzUTC es un Calendar estático objeto correspondiente a UTC zona horaria.

public static final Calendar tzUTC = Calendar.getInstance(TimeZone.getTimeZone("UTC"));  

Escribir Instant a la base de datos TIMESTAMPTZ :

Instant instant = ...;
Timestamp ts = instant != null ? Timestamp.from(instant) : null;
ps.setTimestamp(col, ts, tzUTC);   // column is TIMESTAMPTZ!

Lectura Instant de la base de datos TIMESTAMPTZ :

Timestamp ts = rs.getTimestamp(col,tzUTC); // column is TIMESTAMPTZ
Instant inst = ts !=null ? ts.toInstant() : null;

Esto funciona de manera segura si su tipo de PG es TIMESTAMPTZ (En ese caso, el calendarUTC no tiene ningún efecto en ese código; pero siempre es recomendable no depender de las zonas horarias predeterminadas). "Con seguridad" significa que el resultado no dependerá de la zona horaria del servidor o de la base de datos , o información de zonas horarias:la operación es completamente reversible y pase lo que pase con la configuración de las zonas horarias, siempre obtendrá el mismo "instante de tiempo" que tenía originalmente en el lado de Java.

Si, en lugar de una marca de tiempo (un instante en la línea de tiempo física), se trata de una fecha-hora local "civil" (es decir, el conjunto de campos {year-month-day hour:min:sec(:msecs)} ), usarías:

  • Java:LocalDateTime (Java 8 o Jodatime).
  • JDBC:java.sql.Timestamp
  • PostgreSQL:TIMESTAMP WITHOUT TIMEZONE (TIMESTAMP )

Leer LocalDateTime de la base de datos TIMESTAMP :

Timestamp ts = rs.getTimestamp(col, tzUTC); //
LocalDateTime localDt = null;
if( ts != null ) 
    localDt =  LocalDateTime.ofInstant(Instant.ofEpochMilli(ts.getTime()), ZoneOffset.UTC);

Escriba LocalDateTime a la base de datos TIMESTAMP :

  Timestamp ts = null;
  if( localDt != null)    
      ts = new Timestamp(localDt.toInstant(ZoneOffset.UTC).toEpochMilli()), tzUTC);
  ps.setTimestamp(colNum,ts, tzUTC); 

De nuevo, esta estrategia es segura y puedes dormir tranquilo:si almacenaste 2011-10-30 23:59:30 , recuperará esos campos precisos (hora =23, minuto =59 ... etc.) siempre, pase lo que pase, incluso si mañana cambia la zona horaria de su servidor Postgresql (o cliente), o su JVM o la zona horaria de su sistema operativo, o si tu país modifica sus reglas de horario de verano, etc.

Agregado:si desea (parece un requisito natural) almacenar la especificación de fecha y hora completa (un ZonedDatetime :la marca de tiempo junto con la zona horaria, que implícitamente también incluye la información civil completa de fecha y hora, más la zona horaria)... entonces tengo malas noticias para usted:PostgreSQL no tiene un tipo de datos para esto (ni otras bases de datos, que yo sepa) . Debe diseñar su propio almacenamiento, quizás en un par de campos:podrían ser los dos tipos anteriores (altamente redundantes, aunque eficientes para la recuperación y el cálculo), o uno de ellos más el desplazamiento de tiempo (pierde la información de la zona horaria, algunos cálculos se vuelven difícil y algunos imposibles), o uno de ellos más la zona horaria (como cadena; algunos cálculos pueden ser extremadamente costosos).