PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Qual è il modo più consigliato per memorizzare il tempo in PostgreSQL usando Java?

Qualsiasi strategia per l'archiviazione di dati di data e ora in PostgreSQL dovrebbe, IMO, fare affidamento su questi due punti:

  • La tua soluzione dovrebbe mai dipendono dall'impostazione del fuso orario del server o del client.
  • Attualmente, PostgreSQL (come la maggior parte dei database) non ha un tipo di dati per memorizzare un completo data e ora con fuso orario. Quindi, devi decidere tra un Instant o un LocalDateTime tipo di dati.

Segue la mia ricetta.

Se desideri registrare il istante fisico al momento in cui si è verificato un particolare evento, (un vero "timestamp " , in genere qualche evento di creazione/modifica/eliminazione), quindi utilizza:

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

(Non lasciare che i tipi di dati peculiari di PostgreSQL siano WITH TIMEZONE /WITHOUT TIMEZONE ti confondono:nessuno di loro memorizza effettivamente un fuso orario)

Alcuni codici standard:quanto segue presuppone che ps è un PreparedStatement , rs un ResultSet e tzUTC è un Calendar statico oggetto corrispondente a UTC fuso orario.

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

Scrivi Instant al database TIMESTAMPTZ :

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

Leggi Instant dal database TIMESTAMPTZ :

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

Funziona in modo sicuro se il tuo tipo di PG è TIMESTAMPTZ (In tal caso, il calendarUTC non ha effetto in quel codice; ma è sempre consigliabile non dipendere dai fusi orari predefiniti). "Sicuro" significa che il risultato non dipenderà dal fuso orario del server o del database o informazioni sui fusi orari:l'operazione è completamente reversibile e, qualunque cosa accada alle impostazioni dei fusi orari, otterrai sempre la stessa "istante di tempo" che avevi originariamente sul lato Java.

Se, invece di un timestamp (un istante sulla linea temporale fisica), hai a che fare con una data e ora locale "civile" (ovvero, l'insieme di campi {year-month-day hour:min:sec(:msecs)} ), useresti:

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

Leggi LocalDateTime dal database TIMESTAMP :

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

Scrivi LocalDateTime al database TIMESTAMP :

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

Anche in questo caso, questa strategia è sicura e puoi dormire sonni tranquilli:se hai memorizzato 2011-10-30 23:59:30 , recupererai quei campi precisi (ora=23, minuto=59... ecc.) sempre, non importa cosa, anche se domani il fuso orario del tuo server (o client) Postgresql cambia, o la tua JVM o il tuo fuso orario del sistema operativo, o se il tuo paese modifica le sue regole per l'ora legale, ecc.

Aggiunto:se si desidera (sembra un requisito naturale) memorizzare la specifica datetime completa (un ZonedDatetime :il timestamp insieme al fuso orario, che include implicitamente anche le informazioni datetime complete - più il fuso orario)... quindi ho una brutta notizia per te:PostgreSQL non ha un tipo di dati per questo (né altri database, per quanto ne so) . Devi ideare il tuo spazio di archiviazione, magari in una coppia di campi:potrebbero essere i due tipi sopra (altamente ridondanti, sebbene efficienti per il recupero e il calcolo), o uno di essi più l'offset temporale (perdi le informazioni sul fuso orario, alcuni calcoli diventano difficile, e alcuni impossibili), o uno di essi più il fuso orario (come stringa; alcuni calcoli possono essere estremamente costosi).