L'état actuel des choses au fil du temps

Depuis l'invention de JDBC et la standardisation de ses interfaces, 20 ans se sont écoulés, et pendant ce temps beaucoup de choses ont changé.

Premièrement, le monde est devenu global et maintenant un serveur peut servir des utilisateurs du monde entier. La vitesse d'Internet est en hausse. Par conséquent, un autre type de données a été ajouté à SQL pour fonctionner avec le temps. Maintenant, les types ressemblent à ceci :

  • DATE - stocke la date : année, mois, jour.
  • TIME - stocke le temps : heures, minutes, secondes.
  • TIMESTAMP - stocke un point précis dans le temps : date, heure et millisecondes.
  • HORODATAGE AVEC FUSEAU HORAIRE - HORODATAGE et fuseau horaire (nom de zone ou décalage).

Deuxièmement, Java a introduit l'API DateTime pour la gestion globale du temps. Il a les classes suivantes :

  • Date et heure :
    • DateLocale
    • Heure locale
  • Moment exact :
    • java.time.Instant
    • java.time.LocalDateTime
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime
  • Heure avec fuseau horaire :
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime

Le troisième point intéressant est que de nombreux clients SQL aimeraient recevoir l'heure du serveur déjà dans leur zone locale . Bien sûr, vous pouvez convertir le temps à la volée, mais ce n'est pas pratique et il y a des erreurs.

Par exemple, je souhaite obtenir toutes les tâches d'aujourd'hui à partir de la base de données. SQL Server a une fonction CURDATE() pour cela. Seulement ici, le serveur est aux États-Unis et je suis au Japon. Et je voudrais qu'il me rende tous les records pour "mon aujourd'hui", et non "son aujourd'hui".

En général, le serveur SQL doit également être capable de travailler intelligemment avec des clients dans différents fuseaux horaires.

Les problèmes modernes exigent des solutions modernes

En principe, les nouveaux types de l'API Java DateTime et les types de SQL peuvent être facilement mappés. Pour représenter le type DATE en Java, vous devez utiliser la classe java.time.LocalDate de l'API JDK 8 DateTime.

Le type TIME de la base de données peut être représenté par deux types de Java : java.time.LocalTime et java.time.OffsetTime . Rien de compliqué non plus.

Un point précis dans le temps, représenté par le type TIMESTAMP dans la base de données, peut être représenté en Java par 4 types :

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

Et enfin, TIMESTAMP WITH TIME ZONE peut être représenté par deux types :

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

Puisque vous êtes déjà familier avec l'API DateTime, vous souvenir de ce sujet ne vous sera pas difficile :)

Je vais l'écrire sous forme de tableau, ce sera donc plus simple :

TYPE SQL TypeJava
DATE java.time.LocalDate
TEMPS java.time.LocalTime
java.time.OffsetTime
HORODATAGE java.time.Instant
java.time.LocalDateTime
java.time.OffsetDateTime
java.time.ZonedDateTime
HORODATAGE AVEC FUSEAU HORAIRE java.time.OffsetDateTime
_

Obtenir la date

J'ai une bonne nouvelle pour toi. Première depuis longtemps. Nous pouvons contourner la limitation de la méthode getDate() , qui renvoie un type Date java.sql.

Le fait est que l'objetensemble de résultatsil existe une autre méthode intéressante - getObject() . Cette méthode prend deux paramètres : une colonne et un type, et renvoie la valeur de la colonne convertie dans le type donné. La forme générale de la méthode est la suivante :

ClassName Name = getObject(column, ClassName);

Et si vous voulez convertir le type DATE en type java.time.LocalDate , alors vous devez écrire quelque chose comme :

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

Et tout TIMESTAMP en général peut être converti en un tas de types :

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);

Important! Ce code ne fonctionnera pas si vous avez un pilote MySQL JDBC obsolète . Faites attention à la version de "mysql-connector-java" écrite dans votre pom.xml, ou ajoutée aux bibliothèques dans les paramètres du projet.

Au fait, de la même manière, vous pouvez contourner l'impossibilité de stocker null pour les types primitifs. Si une colonne de table est de type INT, il existe plusieurs façons d'obtenir une valeur nulle à partir de celle-ci. Voir exemple ci-dessous :

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

Réglage du fuseau horaire dans MySQL

Beaucoup de choses intéressantes se sont également produites avec MySQL. Comme vous le savez, lors de la création d'une connexion MySQL, vous pouvez y ajouter divers paramètres :
mysql://localhost:3306/db_scheme?Name=meaning&Name=meaning

Ainsi, trois paramètres ont été ajoutés pour fonctionner avec les fuseaux horaires dans MySQL. Vous pouvez transmettre ces paramètres lorsque vous établissez une connexion au serveur.

Ci-dessous, je vais donner un tableau avec eux:

Paramètre Valeurs Valeur par défaut
connectionTimeZoneconnectionTimeZone LOCALE | SERVEUR | zone utilisateur SERVEUR
forceConnectionTimeZoneToSessionforceConnectionTimeZoneToSession vrai | FAUX vrai
préserverInstants vrai | FAUX FAUX

À l'aide du paramètre connectionTimeZone , nous sélectionnons le fuseau horaire (fuseau horaire) dans lequel toutes les demandes seront exécutées. Du point de vue du client, le serveur s'exécute dans le fuseau horaire spécifié.

Le paramètre forceConnectionTimeZoneToSession entraîne l'ignorance de la variable time_zone de session et son remplacement par connectionTimeZone.

Enfin, le paramètre preserveInstants contrôle la conversion de l'heure exacte entre le timeZone de la JVM et connectionTimeZone.

Les configurations les plus courantes sont :

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=false - correspond à l'ancien pilote MySQL JDBC version 5.1 avec useLegacyDatetimeCode=true.

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=true est un nouveau mode qui offre le moyen le plus naturel de gérer les valeurs de date et d'heure.

  • connectionTimeZone=SERVER & preserveInstants=true - Correspond à l'ancien pilote MySQL JDBC version 5.1 avec useLegacyDatetimeCode=false.

  • connectionTimeZone=user_defined & preserveInstants=true - Aide à surmonter la situation où le fuseau horaire du serveur ne peut pas être reconnu par le connecteur car il est défini comme une abréviation générique telle que CET/CEST.

Oui, les dates sont un sujet intéressant et elles posent de nombreux problèmes. Comme dit le proverbe : ça fait peur, bien sûr, mais je ne suis pas énervé non plus ! :)