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 ! :)
GO TO FULL VERSION