Dagens tilstand over tid

Siden tiden da JDBC ble oppfunnet og grensesnittene ble standardisert, har det gått 20 år, og i løpet av denne tiden har mye endret seg.

For det første har verden blitt global og nå kan én server betjene brukere fra hele verden. Internett-hastigheten er oppe. Derfor ble en annen datatype lagt til SQL for å jobbe med tiden. Nå ser typene slik ut:

  • DATO - lagrer datoen: år, måned, dag.
  • TID - lagrer tid: timer, minutter, sekunder.
  • TIMESTAMP - lagrer et bestemt tidspunkt: dato, klokkeslett og millisekunder.
  • TIDSSTEMPEL MED TIDSSONE - TIDSSTIMPEL og tidssone (sonenavn eller forskyvning).

For det andre introduserte Java DateTime API for global tidsstyring. Den har følgende klasser:

  • Dato og tid :
    • LocalDate
    • Lokal tid
  • Nøyaktig øyeblikk :
    • java.time.Instant
    • java.time.LocalDateTime
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime
  • Tid med tidssone :
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime

Det tredje interessante poenget er at mange SQL-klienter ønsker å motta tid fra serveren allerede i sin lokale sone . Selvfølgelig kan du konvertere tid på farten, men det er ikke praktisk, og det er feil.

For eksempel vil jeg hente alle oppgavene for i dag fra databasen. SQL Server har en CURDATE() -funksjon for dette. Bare her er serveren i USA, og jeg er i Japan. Og jeg vil at han skal returnere alle platene for "min i dag", og ikke "hans i dag".

Generelt må SQL-serveren også kunne jobbe smart med klienter i ulike tidssoner.

Moderne problemer krever moderne løsninger

I prinsippet kan nye typer fra Java DateTime API og typer fra SQL enkelt kartlegges. For å representere DATE- typen i Java, må du bruke klassen java.time.LocalDate fra JDK 8 DateTime API.

TIME-typen fra databasen kan representeres av to typer fra Java: java.time.LocalTime og java.time.OffsetTime . Ikke noe komplisert heller.

Et spesifikt tidspunkt, representert av TIMESTAMP -typen i databasen, kan representeres i Java med 4 typer:

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

Og til slutt kan TIMESTAMP WITH TIME SONE representeres av to typer:

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

Siden du allerede er kjent med DateTime API, vil det ikke være vanskelig for deg å huske denne saken :)

Jeg vil skrive det i form av en tabell, så det blir enklere:

SQL TYPE Java Type
DATO java.time.LocalDate
TID java.time.LocalTime
java.time.OffsetTime
TIDSSTIMPEL java.time.Instant
java.time.LocalDateTime
java.time.OffsetDateTime
java.time.ZonedDateTime
TIDSSTIMPEL MED TIDSSONE java.time.OffsetDateTime
_

Får datoen

Jeg har gode nyheter til deg. Først på lenge. Vi kan komme rundt begrensningen til getDate()- metoden , som returnerer en java.sql-datotype.

Poenget er at objektetresultatsettdet er en annen interessant metode - getObject() . Denne metoden tar to parametere: en kolonne og en type, og returnerer verdien av kolonnen konvertert til den gitte typen. Den generelle formen for metoden er som følger:

ClassName Name = getObject(column, ClassName);

Og hvis du vil konvertere DATO- typen til java.time.LocalDate- typen , må du skrive noe sånt som:

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

Og et hvilket som helst TIMESTAMP generelt kan konverteres til en rekke 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);

Viktig! Denne koden vil ikke fungere hvis du har en utdatert MySQL JDBC-driver . Vær oppmerksom på versjonen av "mysql-connector-java" skrevet i din pom.xml, eller lagt til bibliotekene i prosjektinnstillingene.

Forresten, på samme måte kan du komme deg rundt manglende evne til å lagre null for primitive typer. Hvis en tabellkolonne er av typen INT, er det et par måter å 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

Tidssoneinnstilling i MySQL

Mye interessante ting skjedde også med MySQL. Som du vet, når du oppretter en MySQL-tilkobling, kan du legge til forskjellige parametere til den :
mysql://localhost:3306/db_scheme?Name=meaning&Name=meaning

Så tre parametere er lagt til for å fungere med tidssoner i MySQL. Du kan sende disse parameterne når du oppretter en tilkobling til serveren.

Nedenfor vil jeg gi en tabell med dem:

Parameter Verdier Standardverdi
tilkoblingstidssone LOKAL | SERVER | brukersone SERVER
forceConnectionTimeZoneToSession sant | falsk ekte
bevarInstants sant | falsk falsk

Ved å bruke parameteren connectionTimeZone velger vi tidssonen (tidssonen) der alle forespørsler skal utføres. Fra klientens synspunkt kjører serveren i den angitte tidssonen.

ForceConnectionTimeZoneToSession -parameteren fører til at session time_zone-variabelen ignoreres og erstattes med connectionTimeZone.

Til slutt kontrollerer preserveInstants- parameteren den nøyaktige tidskonverteringen mellom JVMs tidssone og connectionTimeZone.

De vanligste konfigurasjonene er:

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=false - tilsvarer den gamle MySQL JDBC-driveren versjon 5.1 med useLegacyDatetimeCode=true.

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=true er en ny modus som gir den mest naturlige måten å håndtere dato- og tidsverdier på.

  • connectionTimeZone=SERVER & preserveInstants=true - Tilsvarer den gamle MySQL JDBC-driveren versjon 5.1 med useLegacyDatetimeCode=false.

  • connectionTimeZone=user_defined & preserveInstants=true - Hjelper med å overvinne situasjonen der serverens tidssone ikke kan gjenkjennes av koblingen fordi den er satt som en generisk forkortelse som CET/CEST.

Ja, datoer er et interessant tema, og det er mange problemer med dem. Som det sies: det er skummelt, selvfølgelig, men jeg er heller ikke forbanna! :)