sql >> Database >  >> RDS >> PostgreSQL

Wat is de meest aanbevolen manier om tijd op te slaan in PostgreSQL met Java?

Elke strategie voor het opslaan van datum- en tijdgegevens in PostgreSQL zou, IMO, op deze twee punten moeten vertrouwen:

  • Uw oplossing mag nooit afhankelijk van de tijdzone-instelling van de server of client.
  • Momenteel heeft PostgreSQL (zoals de meeste databases) geen datatype om een ​​volledige op te slaan datum en tijd met tijdzone. U moet dus kiezen tussen een Instant of een LocalDateTime gegevenstype.

Mijn recept volgt.

Als je het fysieke moment . wilt opnemen wanneer een bepaalde gebeurtenis plaatsvond, (een echte "tijdstempel " , meestal een aanmaak-/aanpassings-/verwijderingsgebeurtenis), gebruik dan:

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

(Laat PostgreSQL eigenaardige datatypes niet WITH TIMEZONE /WITHOUT TIMEZONE verwar je:geen van hen slaat echt een tijdzone op)

Sommige standaardcode:het volgende gaat ervan uit dat ps is een PreparedStatement , rs een ResultSet en tzUTC is een statische Calendar object dat overeenkomt met UTC tijdzone.

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

Schrijf Instant naar database TIMESTAMPTZ :

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

Lees Instant uit database TIMESTAMPTZ :

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

Dit werkt veilig als uw PG-type TIMESTAMPTZ is (In dat geval is de calendarUTC heeft geen effect in die code; maar het is altijd aan te raden om niet afhankelijk te zijn van standaard tijdzones). "Veilig" betekent dat het resultaat niet afhankelijk is van de tijdzone van de server of database , of tijdzone-informatie:de bewerking is volledig omkeerbaar en wat er ook gebeurt met de tijdzone-instellingen, u krijgt altijd hetzelfde "instant tijd" dat u oorspronkelijk had aan de Java-kant.

Als je, in plaats van een tijdstempel (een moment op de fysieke tijdlijn), te maken hebt met een "civiele" lokale datum-tijd (dat wil zeggen, de set velden {year-month-day hour:min:sec(:msecs)} ), zou je gebruiken:

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

Lees LocalDateTime uit database TIMESTAMP :

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

Schrijf LocalDateTime naar database TIMESTAMP :

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

Nogmaals, deze strategie is veilig en je kunt rustig slapen:als je 2011-10-30 23:59:30 hebt opgeslagen , haalt u die precieze velden (uur=23, minuut=59... enz.) altijd op, wat er ook gebeurt - zelfs als morgen de tijdzone van uw Postgresql-server (of client) verandert, of uw JVM of uw OS-tijdzone, of als uw land de DST-regels wijzigt, enz.

Toegevoegd:als je wilt (het lijkt een natuurlijke vereiste) om de volledige datetime-specificatie op te slaan (een ZonedDatetime :de tijdstempel samen met de tijdzone, die impliciet ook de volledige burgerlijke datetime-info bevat - plus de tijdzone)... dan heb ik slecht nieuws voor je:PostgreSQL heeft hier geen datatype voor (noch andere databases, voor zover ik weet) . U moet uw eigen opslag bedenken, misschien in een paar velden:dit kunnen de twee bovenstaande typen zijn (zeer overbodig, maar efficiënt voor ophalen en berekenen), of een van hen plus de tijdverschuiving (u verliest de tijdzone-informatie, sommige berekeningen worden moeilijk, en sommige onmogelijk), of een van hen plus de tijdzone (als string; sommige berekeningen kunnen extreem duur zijn).



  1. Een kolomtype wijzigen in langere strings in rails

  2. Oracle Concurrent Manager – CP Analyzer voor E-Business Suite

  3. Hoe kan ik null-waarden opnemen in een MIN of MAX?

  4. Kan een refererende sleutel verwijzen naar een niet-unieke index?