Den aktuelle situation over tid

Siden dengang JDBC blev opfundet og dets grænseflader blev standardiseret, er der gået 20 år, og i løbet af denne tid har mange ting ændret sig.

For det første er verden blevet global, og nu kan én server betjene brugere fra hele verden. Internethastigheden er op. Derfor blev der tilføjet en anden datatype til SQL for at arbejde med tiden. Nu ser typerne sådan ud:

  • DATO - gemmer datoen: år, måned, dag.
  • TID - gemmer tid: timer, minutter, sekunder.
  • TIMESTAMP - gemmer et bestemt tidspunkt: dato, tid og millisekunder.
  • TIDSSTYKKE MED TIDZONE - TIDSSTYKKE og tidszone (zonenavn eller offset).

For det andet introducerede Java DateTime API til global tidsstyring. Den har følgende klasser:

  • Dato og tid :
    • LocalDate
    • Lokal tid
  • Præcis øjeblik :
    • java.time.Instant
    • java.time.LocalDateTime
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime
  • Tid med tidszone :
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime

Det tredje interessante punkt er, at mange SQL-klienter gerne vil modtage tid fra serveren allerede i deres lokale zone . Selvfølgelig kan du konvertere tid i farten, men det er ikke praktisk, og der er fejl.

For eksempel vil jeg hente alle dagens opgaver fra databasen. SQL Server har en CURDATE() funktion til dette. Kun her er serveren i USA, og jeg er i Japan. Og jeg vil gerne have, at han returnerer alle pladerne for "min i dag", og ikke "hans i dag".

Generelt skal SQL-serveren også kunne arbejde smart med klienter i forskellige tidszoner.

Moderne problemer kræver moderne løsninger

I princippet kan nye typer fra Java DateTime API og typer fra SQL nemt kortlægges. For at repræsentere DATE- typen i Java skal du bruge klassen java.time.LocalDate fra JDK 8 DateTime API.

TIME-typen fra databasen kan repræsenteres af to typer fra Java: java.time.LocalTime og java.time.OffsetTime . Heller ikke noget kompliceret.

Et specifikt tidspunkt, repræsenteret af TIMESTAMP -typen i databasen, kan repræsenteres i Java med 4 typer:

  • java.time.Instant
  • java.time.LocalDateTime
  • java.time.OffsetDateTime
  • java.time.ZonedDateTime

Og endelig kan TIMESTAMP WITH TIME ZONE repræsenteres af to typer:

  • java.time.OffsetDateTime
  • java.time.ZonedDateTime

Da du allerede er bekendt med DateTime API, vil det ikke være svært for dig at huske denne sag :)

Jeg vil skrive det i form af en tabel, så det bliver nemmere:

SQL TYPE Java type
DATO java.time.LocalDate
TID java.time.LocalTime
java.time.OffsetTime
TIDSSTEMPEL java.time.Instant
java.time.LocalDateTime
java.time.OffsetDateTime
java.time.ZonedDateTime
TIDSSTIMPEL MED TIDZONE java.time.OffsetDateTime
_

Får datoen

Jeg har en god nyhed til dig. Først i lang tid. Vi kan komme uden om begrænsningen af ​​getDate() metoden , som returnerer en java.sql datotype.

Pointen er, at objektetresultatsætder er en anden interessant metode - getObject() . Denne metode tager to parametre: en kolonne og en type og returnerer værdien af ​​kolonnen konverteret til den givne type. Metodens generelle form er som følger:

ClassName Name = getObject(column, ClassName);

Og hvis du vil konvertere DATE- typen til java.time.LocalDate- typen , så skal du skrive noget som:

LocalDate localDate = results.getObject(4, LocalDate.class);

Og ethvert TIMESTAMP generelt kan konverteres til en masse typer:

java.time.Instant instant = results.getObject(9, java.time.Instant.class);
java.time.LocalDateTime local = results.getObject(9, java.time. LocalDateTime.class);
java.time.OffsetDateTime offset = results.getObject(9, java.time. OffsetDateTime.class);
java.time.ZonedDateTime zoned = results.getObject(9, java.time. ZonedDateTime.class);

Vigtig! Denne kode virker ikke, hvis du har en forældet MySQL JDBC-driver . Vær opmærksom på versionen af ​​"mysql-connector-java" skrevet i din pom.xml, eller tilføjet til bibliotekerne i projektindstillingerne.

I øvrigt kan du på samme måde komme uden om manglende evne til at gemme null for primitive typer. Hvis en tabelkolonne er af typen INT, så er der et par måder at få null fra den. Se eksempel nedenfor:

Integer id1 = results.getObject(8, Integer.class);    	 // this will work
Integer id2 = results.getObject(8, int.class);                 //this will also work
int id3 = results.getObject(8,  Integer.class);            	//method will return null, JVM will throw NPE
int id4 = results.getObject(8,  int.class);                    	//method will return null, JVM will throw NPE

Tidszoneindstilling i MySQL

Der skete også mange interessante ting med MySQL. Som du ved, når du opretter en MySQL-forbindelse, kan du tilføje forskellige parametre til den :
mysql://localhost:3306/db_scheme?Name=meaning&Name=meaning

Så der er tilføjet tre parametre for at arbejde med tidszoner i MySQL. Du kan videregive disse parametre, når du etablerer en forbindelse til serveren.

Nedenfor vil jeg give en tabel med dem:

Parameter Værdier Standard værdi
forbindelseTimeZone LOKAL | SERVER | bruger-zone SERVER
forceConnectionTimeZoneToSession sandt | falsk rigtigt
bevarInstants sandt | falsk falsk

Ved at bruge parameteren connectionTimeZone vælger vi den tidszone (tidszone), hvor alle anmodninger vil blive udført. Fra klientens synspunkt kører serveren i den angivne tidszone.

ForceConnectionTimeZoneToSession -parameteren får sessions-tidszone-variablen til at blive ignoreret og erstattet med connectionTimeZone.

Endelig kontrollerer parameteren preserveInstants den nøjagtige tidskonvertering mellem JVM's tidszone og forbindelsestidszone.

De mest almindelige konfigurationer er:

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=false - svarer til den gamle MySQL JDBC-driver version 5.1 med useLegacyDatetimeCode=true.

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=true er en ny tilstand, der giver den mest naturlige måde at håndtere dato- og tidsværdier på.

  • connectionTimeZone=SERVER & preserveInstants=true - Svarer til den gamle MySQL JDBC-driver version 5.1 med useLegacyDatetimeCode=false.

  • connectionTimeZone=user_defined & preserveInstants=true - Hjælper med at overvinde situationen, hvor serverens tidszone ikke kan genkendes af connectoren, fordi den er indstillet som en generisk forkortelse såsom CET/CEST.

Ja, datoer er et interessant emne, og der er mange problemer med dem. Som man siger: det er selvfølgelig skræmmende, men jeg er heller ikke sur! :)