PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Quelle est la méthode la plus recommandée pour stocker l'heure dans PostgreSQL en utilisant Java ?

Toute stratégie de stockage de données de date et d'heure dans PostgreSQL devrait, à mon avis, s'appuyer sur ces deux points :

  • Votre solution ne devrait jamais dépendent du paramètre de fuseau horaire du serveur ou du client.
  • Actuellement, PostgreSQL (comme la plupart des bases de données) n'a pas de type de données pour stocker un complet date et heure avec fuseau horaire. Vous devez donc choisir entre un Instant ou un LocalDateTime type de données.

Ma recette suit.

Si vous souhaitez enregistrer l'instant physique au moment où un événement particulier s'est produit, (un vrai "timestamp " , généralement un événement de création/modification/suppression), puis utilisez :

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

(Ne laissez pas les types de données propres à PostgreSQL WITH TIMEZONE /WITHOUT TIMEZONE vous confondre :aucun d'entre eux ne stocke réellement un fuseau horaire)

Du code passe-partout :ce qui suit suppose que ps est un PreparedStatement , rs un ResultSet et tzUTC est un Calendar statique objet correspondant à UTC fuseau horaire.

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

Écrire Instant à la base de données TIMESTAMPTZ :

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

Lire Instant de la base de données TIMESTAMPTZ :

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

Cela fonctionne en toute sécurité si votre type de PG est TIMESTAMPTZ (Dans ce cas, le calendarUTC n'a aucun effet dans ce code; mais il est toujours conseillé de ne pas dépendre des fuseaux horaires par défaut)."En toute sécurité" signifie que le résultat ne dépendra pas du fuseau horaire du serveur ou de la base de données , ou informations sur les fuseaux horaires :l'opération est entièrement réversible, et quoi qu'il advienne des paramètres de fuseaux horaires, vous obtiendrez toujours le même "instant de temps" que vous aviez à l'origine du côté Java.

Si, au lieu d'un horodatage (un instant sur la timeline physique), vous avez affaire à une date-heure locale "civile" (c'est-à-dire l'ensemble des champs {year-month-day hour:min:sec(:msecs)} ), vous utiliseriez :

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

Lire LocalDateTime de la base de données TIMESTAMP :

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

Ecrire LocalDateTime à la base de données TIMESTAMP :

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

Encore une fois, cette stratégie est sûre et vous pouvez dormir paisiblement :si vous avez enregistré 2011-10-30 23:59:30 , vous récupérerez toujours ces champs précis (heure=23, minute=59... etc) quoi qu'il arrive - même si demain le fuseau horaire de votre serveur (ou client) Postgresql change, ou votre JVM ou le fuseau horaire de votre système d'exploitation, ou si votre pays modifie ses règles d'heure d'été, etc.

Ajout :Si vous souhaitez (cela semble une exigence naturelle) stocker la spécification datetime complète (un ZonedDatetime :l'horodatage avec le fuseau horaire, qui inclut implicitement également les informations civiles complètes sur la date et l'heure - plus le fuseau horaire)... alors j'ai une mauvaise nouvelle pour vous :PostgreSQL n'a pas de type de données pour cela (ni d'autres bases de données, à ma connaissance) . Vous devez concevoir votre propre stockage, peut-être dans une paire de champs :il peut s'agir des deux types ci-dessus (très redondants, mais efficaces pour la récupération et le calcul), ou l'un d'eux plus le décalage horaire (vous perdez les informations sur le fuseau horaire, certains calculs deviennent difficile et parfois impossible), ou l'un d'eux plus le fuseau horaire (sous forme de chaîne ; certains calculs peuvent être extrêmement coûteux).