PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Was ist die am meisten empfohlene Methode zum Speichern von Zeit in PostgreSQL mit Java?

Jede Strategie zum Speichern von Datums- und Uhrzeitdaten in PostgreSQL sollte sich meiner Meinung nach auf diese beiden Punkte stützen:

  • Ihre Lösung sollte niemals hängen von der Zeitzoneneinstellung des Servers oder Clients ab.
  • Derzeit hat PostgreSQL (wie die meisten Datenbanken) keinen Datentyp zum Speichern eines vollständigen Datum und Uhrzeit mit Zeitzone. Sie müssen sich also zwischen einem Instant entscheiden oder eine LocalDateTime Datentyp.

Mein Rezept folgt.

Wenn Sie den physischen Augenblick aufzeichnen möchten wann ein bestimmtes Ereignis aufgetreten ist (ein echter "Zeitstempel " , normalerweise ein Ereignis zum Erstellen/Ändern/Löschen), verwenden Sie dann:

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

(Lassen Sie keine PostgreSQL-spezifischen Datentypen WITH TIMEZONE /WITHOUT TIMEZONE verwirren:keiner von ihnen speichert tatsächlich eine Zeitzone)

Etwas Boilerplate-Code:Im Folgenden wird davon ausgegangen, dass ps ist ein PreparedStatement , rs ein ResultSet und tzUTC ist ein statischer Calendar Objekt, das UTC entspricht Zeitzone.

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

Schreiben Sie Instant in die Datenbank TIMESTAMPTZ :

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

Lesen Sie Instant aus der Datenbank TIMESTAMPTZ :

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

Dies funktioniert sicher, wenn Ihr PG-Typ TIMESTAMPTZ ist (In diesem Fall wird die calendarUTC hat in diesem Code keine Auswirkung; aber es ist immer ratsam, sich nicht auf die Standardzeitzonen zu verlassen). "Sicher" bedeutet, dass das Ergebnis nicht von der Server- oder Datenbankzeitzone abhängt , oder Zeitzoneninformationen:Der Vorgang ist vollständig umkehrbar, und was auch immer mit den Zeitzoneneinstellungen passiert, Sie erhalten immer denselben "Zeitpunkt", den Sie ursprünglich auf der Java-Seite hatten.

Wenn Sie es anstelle eines Zeitstempels (ein Moment auf der physischen Zeitachse) mit einer "zivilen" lokalen Datumszeit zu tun haben (d. h. der Satz von Feldern {year-month-day hour:min:sec(:msecs)} ), würden Sie Folgendes verwenden:

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

Lesen Sie LocalDateTime aus der Datenbank TIMESTAMP :

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

Schreiben Sie LocalDateTime in die Datenbank TIMESTAMP :

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

Auch diese Strategie ist sicher und Sie können ruhig schlafen:Wenn Sie 2011-10-30 23:59:30 gespeichert haben , werden Sie diese genauen Felder (Stunde =23, Minute =59 ... usw.) immer abrufen, egal was passiert - selbst wenn sich morgen die Zeitzone Ihres Postgresql-Servers (oder Clients) oder Ihrer JVM oder Ihrer OS-Zeitzone ändert, oder wenn Ihr Land seine DST-Regeln ändert usw.

Hinzugefügt:Wenn Sie möchten (es scheint eine natürliche Anforderung zu sein), die vollständige datetime-Spezifikation zu speichern (eine ZonedDatetime :der Zeitstempel zusammen mit der Zeitzone, die implizit auch die vollständigen bürgerlichen Datums- und Uhrzeitinformationen enthält - plus die Zeitzone) ... dann habe ich schlechte Nachrichten für Sie:PostgreSQL hat keinen Datentyp dafür (meines Wissens auch keine anderen Datenbanken) . Sie müssen Ihren eigenen Speicher entwickeln, vielleicht in zwei Feldern:Es könnten die beiden oben genannten Typen sein (hochredundant, aber effizient für Abruf und Berechnung) oder einer davon plus Zeitversatz (Sie verlieren die Zeitzoneninformationen, einige Berechnungen werden schwierig und einige unmöglich), oder eine davon plus die Zeitzone (als Zeichenfolge; einige Berechnungen können extrem kostspielig sein).