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

Lagring af aftaler i en SQL-database såsom Postgres til brug med java.time framework

Det afhænger af typen af ​​aftale.

Der er to slags aftaler:

  • Et øjeblik, et bestemt punkt på tidslinjen, ignorerer eventuelle ændringer i tidszonereglerne.
    Eksempel:Raketaffyring.
  • En dato og et klokkeslæt, der bør justeres for ændringer i tidszonereglerne.
    Eksempel:Læge-/tandlægebesøg.

Øjeblik

Hvis vi for eksempel bestiller affyring af en raket, er vi ligeglade med datoen og tidspunktet på dagen. Vi bekymrer os kun om det øjeblik, hvor (a) himlen er på linje, og (b) vi forventer gunstigt vejr.

Hvis politikerne i den mellemliggende tid ændrer reglerne for den tidszone, der er i brug på vores lanceringssted eller på vores kontorer, har det ingen betydning for vores lanceringsaftale. Hvis politikere, der styrer vores lanceringsside, vedtager sommertid (DST) , tidspunktet for vores lancering forbliver det samme. Hvis politikerne, der styrer vores kontorer, beslutter at skift uret en halv time tidligere på grund af diplomatiske forbindelser med et naboland forbliver tidspunktet for vores lancering det samme.

For sådan en udnævnelse, ja, din tilgang ville være korrekt. Du ville optage aftalen i UTC ved hjælp af en kolonne af typen TIMESTAMP WITH TIME ZONE . Efter hentning skal du justere til enhver tidszone, som brugeren foretrækker.

Databaser såsom Postgres bruge enhver tidszoneinformation, der ledsager et input, til at justere til UTC, og derefter bortskaffe denne tidszoneinformation. Når du henter værdien fra Postgres, vil den altid repræsentere en dato med klokkeslæt som set i UTC. Pas på, nogle værktøjer eller middleware kan have den anti-funktion at anvende en standardtidszone mellem hentning fra databasen og levering til dig, programmøren. Men vær tydelig:Postgres gemmer og henter altid værdier af typen TIMESTAMP WITH TIME ZONE i UTC, altid UTC og offset-from-UTC på nul timer-minutter-sekunder.

Her er et eksempel på Java-kode.

LocalDate launchDateAsSeenInRome = LocalDate.of( 2021 , 1 , 23 ) ;
LocalTime launchTimeAsSeenInRome = LocalTime.of( 21 , 0 ) ;
ZoneId zoneEuropeRome = ZoneId.of( "Europe/Rome" ) ;
// Assemble those three parts to determine a moment.
ZonedDateTime launchMomentAsSeenInRome = ZonedDateTime.of( launchDateAsSeenInRome , launchTimeAsSeenInRome , zoneEuropeRome ) ;

For at se det samme øjeblik i UTC skal du konvertere til et Instant . Et Instant objekt repræsenterer altid et øjeblik som set i UTC.

Instant launchInstant = launchMomentAsSeenInRome.toInstant() ;  // Adjust from Rome time zone to UTC.

Z i slutningen af ​​ovenstående strengeksempel er standardnotation for UTC og udtales "Zulu".

Desværre forsømte JDBC 4.2-teamet at kræve support til enten Instant eller ZonedDateTime typer. Så din JDBC-driver kan eller måske ikke være i stand til at læse/skrive sådanne objekter til din database. Hvis ikke, skal du blot konvertere til OffsetDateTime . Alle tre typer repræsenterer et øjeblik, et bestemt punkt på tidslinjen. Men OffsetDateTime har support påkrævet af JDBC 4.2 af årsager, der undslipper mig.

OffsetDateTime odtLaunchAsSeenInRome = launchMomentAsSeenInRome.toOffsetDateTime() ;

Skriver til database.

myPreparedStatement.setObject( … , odtLaunchAsSeenInRome ) ;

Hentning fra database.

OffsetDateTime launchMoment = myResultSet.getObject( … , OffsetDateTime.class ) ;

Juster til den New York-tidszone, som din bruger ønsker.

ZoneId zoneAmericaNewYork = ZoneId.of( "America/New_York" ) ;
ZonedDateTime launchAsSeenInNewYork = launchMoment.atZoneSameInstant( zoneAmericaNewYork ) ;

Du kan se alle ovenstående kode køres live på IdeOne.com .

Forresten behandles sporing af tidligere begivenheder også som et øjeblik. Hvornår ankom patienten faktisk til en aftale, hvornår betalte kunden fakturaen, hvornår underskrev en ny ansat deres dokumenter, hvornår gik serveren ned... alt dette spores som et øjeblik i UTC. Som diskuteret ovenfor vil det normalt være et Instant , selvom ZonedDateTime &OffsetDateTime repræsenterer også et øjeblik. Brug TIMESTAMP WITH TIME ZONE til databasen (ikke UDEN ).

Tid på dagen

Jeg forventer, at de fleste forretningsorienterede apps er fokuseret på aftaler af den anden type, hvor vi sigter mod en dato med et tidspunkt på dagen frem for et specifikt øjeblik.

Hvis brugeren laver en aftale med sin sundhedsplejerske for at gennemgå resultaterne af en test, gør de det på et bestemt tidspunkt på dagen på denne dato. Hvis politikerne i mellemtiden ændrer reglerne for deres tidszone, flytter uret frem eller bagud en time eller en halv time eller et hvilket som helst andet tidsrum, forbliver datoen og klokkeslættet for den lægesamtale den samme. I virkeligheden vil tidspunktet for den oprindelige udnævnelse blive ændret, efter at politikerne ændrer tidszonen, og skifter til et tidligere/senere tidspunkt på tidslinjen.

For sådanne aftaler gør vi ikke gemme dato og klokkeslæt som vist i UTC. Det gør vi ikke brug databasekolonnetypen TIMESTAMP WITH TIME ZONE .

For sådanne aftaler gemmer vi datoen med klokkeslæt uden hensyn til tidszone. Vi bruger en databasekolonne af typen TIMESTAMP WITHOUT TIME ZONE (bemærk UDEN i stedet for WITH ). Den matchende type i Java er LocalDateTime .

LocalDate medicalApptDate = LocalDate.of( 2021 , 1 , 23 ) ;
LocalTime medicalApptTime = LocalTime.of( 21 , 0 ) ;
LocalDateTime medicalApptDateTime = LocalDateTime.of( medicalApptDate , medicalApptTime ) ;

Skriv det til databasen.

myPreparedStatement.setObject( … , medicalApptDateTime ) ;

Vær klar over dette:en LocalDateTime objektet ikke repræsentere et øjeblik, er ikke et bestemt punkt på tidslinjen. En LocalDateTime objekt repræsenterer en række mulige øjeblikke langs omkring 26-27 timer af tidslinjen (intervallet af tidszoner rundt om på kloden). At give reel mening til en LocalDateTime , skal vi tilknytte en påtænkt tidszone.

For den påtænkte tidszone skal du bruge en anden kolonne til at gemme zone-id'et. For eksempel strengene Europa/Rom eller America/New_York . Se liste over zonenavne .

ZoneId zoneEuropeRome = ZoneId.of( "Europe/Rome" ) ;

Skriv det til databasen som tekst.

myPreparedStatement.setString( … , zoneEuropeRome ) ;

Hentning. Hent zonenavnet som tekst, og instansier et ZoneId objekt.

LocalDateTime medicalApptDateTime = myResultSet.getObject( … , LocalDateTime.class ) ;
ZoneId medicalApptZone = ZoneId.of( myResultSet.getString( … ) ) ;

Sæt disse to stykker sammen for at bestemme et øjeblik repræsenteret som en ZonedDateTime objekt. Gør dette dynamisk, når du skal planlægge en kalender. Men gør ikke gemme øjeblikket. Hvis politikerne omdefinerer tidszonen/tidszonerne i fremtiden, skal der så beregnes et andet tidspunkt.

ZonedDateTime medicalApptAsSeenInCareProviderZone = ZonedDateTime.of( medicalApptDateTime , medicalApptZone ) ;

Brugeren rejser til New York USA. De skal vide, hvornår de skal ringe til sundhedsplejersken i Milano Italien ifølge urene på væggen i deres midlertidige placering i New York. Så juster fra en tidszone til en anden. Samme øjeblik, forskellig vægur.

ZoneId zoneAmericaNewYork = ZoneId.of( "America/New_York" ) ;
ZonedDateTime medicalApptAsSeenInNewYork = medicalApptAsSeenInCareProviderZone.withZoneSameInstant( zoneAmericaNewYork ) ;

tzdata

Vær opmærksom på, at hvis reglerne for dine ønskede tidszoner kan ændre sig, skal du opdatere kopien af ​​tidszonedefinitioner på dine computere.

Java indeholder sin egen kopi af tzdata , ligesom Postgres-databasemotoren. Og også dit værtsoperativsystem. Denne særlige kode, der vises her, kræver kun at Java er opdateret. Hvis du bruger Postgres til at foretage tidszonejusteringer, er dets tzdata skal også være opdateret. Og til logning og sådan skal dit værts-OS holdes opdateret. For korrekt ur-overvågning af brugeren skal deres klientmaskines OS også være opdateret.

Pas på:Politikere over hele verden har vist en forkærlighed for at ændre deres tidszoner med overraskende hyppighed og ofte med lidt forvarsel.

Om java.time

java.time framework er indbygget i Java 8 og nyere. Disse klasser erstatter den besværlige gamle arv dato-tidsklasser såsom java.util.Dato , Kalender , &>SimpleDateFormat .

For at lære mere, se Oracle Tutorial . Og søg i Stack Overflow for mange eksempler og forklaringer. Specifikationen er JSR 310 .

Joda-Time projekt, nu i vedligeholdelsestilstand , anbefaler migrering til java.time klasser.

Du kan udveksle java.time objekter direkte med din database. Brug en JDBC-driver i overensstemmelse med JDBC 4.2 eller senere. Intet behov for strenge, intet behov for java.sql.* klasser. Hibernate 5 og JPA 2.2 understøtter java.time .

Hvor får man java.time klasserne?



  1. AWS RDS MySql - hvordan tillader du adgang efter indstilling af 'Offentligt tilgængelig'

  2. Pipelinet funktion kalder en anden pipelinet funktion

  3. Sådan fungerer DATE_FORMAT() i MariaDB

  4. PHP:Sådan vises en variabel (a) i en anden variabel (b), når variabel (b) indeholder tekst