sql >> Database teknologi >  >> RDS >> Oracle

Håndtering af tidszone i webapplikation

Læs de bedste fremgangsmåder for spørgsmålet sommertid og tidszone. Din er dybest set en dublet.

Servere i UTC

Ja, generelt bør servere have deres OS indstillet til UTC som tidszone, eller hvis det ikke er angivet, skal du bruge GMT eller tidszonen Reykjavík Island. Din Java-implementering opfanger sandsynligvis denne indstilling som sin egen nuværende standardtidszone.

Angiv tidszone

Men vær ikke afhængig af, at tidszonen er indstillet til UTC. En sysadmin kunne ændre det. Og enhver Java-kode i enhver tråd i enhver app i din JVM kan ændre JVM's nuværende standardtidszone ved runtime ved at kalde TimeZone.setDefault . Så i stedet skal du gøre det til en vane altid at angive den ønskede/forventede tidszone ved at sende det valgfrie argument i din Java-kode.

Jeg betragter det som en designfejl, at enhver dato-tid-ramme ville gøre tidszonen valgfri. At være valgfri skaber uendelige mængder af forvirring, fordi programmører, som alle andre, ubevidst tænker i deres egen personlige tidszone, medmindre de bliver bedt om det. Så alt for ofte i date-time-arbejde er der ingen opmærksomhed på problemet. Tilføj det problem, at JVM-standarden varierer. Forresten, ditto for Locale , samme problemer, bør altid angives eksplicit.

UTC

Din forretningslogik, datalagring og dataudveksling bør næsten altid foregå i UTC. Næsten hver database har en funktion til justering af input til UTC og lagring i UTC.

Når du præsenterer en dato-klokkeslæt for en bruger, skal du justere til den forventede tidszone. Når du serialiserer en dato-tidsværdi, skal du bruge ISO 8601-strengformaterne. Se svaret af VickyArora for Oracle specifikt (jeg er en Postgres-person). Sørg for at læse dokumentet omhyggeligt, og øv dig ved at eksperimentere for fuldt ud at forstå din databases adfærd. SQL-specifikationen udtaler ikke særlig meget i denne henseende, og adfærd varierer meget.

java.sql

Husk, at når du bruger Java og JDBC, vil du bruge java.sql.Timestamp og relaterede datatyper. De er altid i UTC, automatisk. Forvent i fremtiden at se JDBC-drivere opdateret til direkte at bruge de nye datatyper, der er defineret i java.time-rammeværket indbygget i Java 8 og nyere.

java.time

De gamle klasser er forældede af java.time. Lær at bruge java.time mens du undgår den gamle java.util.Date/.Calendar og gør dit programmeringsliv meget mere behageligt.

Indtil din JDBC-driver er opdateret, kan du bruge konverteringsmetoderne indbygget i java.time. Se eksempler næste, hvor Instant er et øjeblik i UTC og ZonedDateTime er et øjeblik justeret til en tidszone.

Instant instant = myJavaSqlTimestamp.toInstant();
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

For at gå den anden vej.

java.sql.Timestamp myJavaSqlTimestamp = java.sql.Timestamp.from( zdt.toInstant() );

Hvis du har brug for original tidszone, skal du gemme den

Hvis dine forretningskrav anser de originale inputdatas tidszone for at være vigtig, for at blive husket, så gem det eksplicit som en separat kolonne i din databasetabel. Du kan bruge en offset-fra-UTC, men det giver ikke fuld information. En tidszone er en offset plus et sæt regler for tidligere, nuværende og fremtidige håndtering af uregelmæssigheder såsom sommertid. Så et korrekt tidszonenavn er mest passende, såsom America/Montreal .

Kun dato er tvetydig

Du sagde, at du indsamler mange værdier, der kun er på dato, uden tidspunkt på dagen og uden tidszone. Klassen for det i java.time er LocalDate . Som med LocalTime og LocalDateTime , "Lokal..."-delen betyder ingen bestemt lokalitet, så derfor har ingen tidszone, og derfor ikke et punkt på tidslinjen -- ingen reel betydning.

Husk, at en værdi, der kun gælder for dato, er tvetydig per definition. På ethvert givet tidspunkt varierer datoen rundt om i verden. For eksempel, lige efter midnat i Paris er Frankrig en ny dag, men i Montréal Québec er datoen stadig "i går".

Normalt i erhvervslivet er en eller anden tidszone implicit, selv ubevidst intuition. Ubevidst intuition om datapunkter har en tendens til ikke at fungere godt på lang sigt, især i software. Bedre at præcisere, hvilken tidszone der var tiltænkt. Du kan gemme den tilsigtede zone ved siden af ​​datoen, såsom en anden kolonne i databasetabellen, eller du kan lave en kommentar i din programmeringskode. Jeg tror, ​​det ville være langt bedre og sikrere at gemme en dato-tidsværdi. Så hvordan omdanner vi kun en dato til en dato-tid?

Ofte er en ny dag øjeblikket efter midnat, dagens første øjeblik. Du tror måske, at det betyder tidspunktet på dagen 00:00:00.0 men ikke altid. Sommertid (DST) og muligvis andre uregelmæssigheder kan skubbe det første øjeblik til en anden vægur. Lad java.time bestemme det korrekte tidspunkt på dagen for det første øjeblik gennem LocalDate klasse og dens atStartOfDay metode.

ZoneId zoneId = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( zoneId );
ZonedDateTime todayStart = today.atStartOfDay( zoneId );

I nogle forretningssammenhænge kan en ny dag defineres (eller antages) at være arbejdstid. Lad os f.eks. sige, at en udgiver i New York betyder kl. 9.00 i deres lokale tid, når de siger "bogudkastet skal afleveres den 2. januar". Lad os få det tidspunkt på dagen for den dato i den tidszone.

ZoneId zoneId = ZoneId.of( "America/New_York" );
ZonedDateTime zdt = ZonedDateTime.of( 2016 , 1 , 2 , 9 , 0 , 0 , 0 , zoneId );

Hvad betyder det for forfatteren, der arbejder i New Zealand? Juster ind i hendes særlige tidszone til præsentation for hende ved at ringe til withZoneSameInstant .

ZoneId zoneId_Pacific_Auckland = ZoneId.of( "Pacific/Auckland" );
ZonedDateTime zdt_Pacific_Auckland = zdt.withZoneSameInstant( zoneId_Pacific_Auckland );

Database

Til databaselagring transformerer vi til en Instant (et øjeblik på tidslinjen i UTC) og gå videre som en java.sql.Timestamp som set tidligere ovenfor.

java.sql.Timestamp ts = java.sql.Timestamp.from( zdt.toInstant() );

Når den hentes fra databasen, skal du transformere tilbage til en New York-dato-tid. Konverter fra java.sql.Timestamp til et Instant , og anvend derefter en tidszone ZoneId for at få en ZonedDateTime .

Instant instant = ts.toInstant();
ZoneId zoneId = ZoneId.of( "America/New_York" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

Hvis din databasedriver overholder JDBC 4.2 eller nyere, kan du muligvis sende/hente java.time-typerne direkte i stedet for at konvertere til/fra java.sql-typer. Prøv PreparedStatement::setObject og ResultSet::getObject metoder.



  1. Forståelse af Always ON Availability Group mellem Linux-baserede SQL Server-instanser. Del 1

  2. Installation af SQL Server Failover Cluster Instance – Del 1

  3. Sammenligning af virtuelle cloud-maskiner med administreret cloud-database

  4. Træk og slip i MS Access og betinget sortering