Savez-vous quelle est la différence entre les caractères « Y » et « y » dans le modèle de date Java ? Dans cet article, nous explorerons comment un format de date incorrect peut provoquer une erreur. Nous présenterons également notre nouvelle règle de diagnostic V6122 pour Java qui vous évitera un voyage dans le temps soudain.
Après avoir dépoussiéré notre gros carnet TODO, nous sommes tombés sur un cas particulièrement intéressant. Un commentateur de l’article a souligné le problème potentiel.
Le commentaire
Au fait, voici une idée pour vous : SimpleDateFormat en Java peut vous réserver une surprise pour le Nouvel An : une année écrite en lettres minuscules n'est pas la même chose qu'une année écrite en majuscules. Au cours de la dernière semaine de l'année, vous pourriez soudainement vous retrouver dans le futur, car « AAAA » pour les dates du 27.12.2021 au 31.12.2021 est 2022, et non 2021 comme certains pourraient s'y attendre.
Allons au fond des choses.
Si vous avez oublié ce qu'est SimpleDateFormat, vous pouvez parfaire vos connaissances ici.
Pour stocker et afficher les dates, nous avons souvent besoin qu'elles suivent un modèle particulier. SimpleDateFormat est une classe qui nous permet de formater facilement une date selon un modèle donné. En plus du formatage, SimpleDateFormat peut également analyser les chaînes et les convertir en objet date.
Est-ce tout ce que Java a à offrir ? En plus de SimpleDateFormat, la classe DateTimeFormatter peut également formater les dates.
Laissez-moi vous montrer un exemple d'utilisation de ces deux classes.
Si on formate une date via SimpleDateFormat :
public static void main(String[] args) { Date date = new Date("2024/12/31"); var dateFormatter = new SimpleDateFormat("dd-MM-yyyy"); System.out.println(dateFormatter.format(date)); }
La console affiche ce qui suit :
31-12-2024
Que s'est-il passé ici ?
Nous avons une date et nous souhaitons la sauvegarder/l'afficher dans un format spécifique. Pour y parvenir, nous créons l'objet SimpleDateFormat en passant une chaîne de modèle au constructeur. La date est formatée exactement selon ce modèle. La méthode format renvoie une représentation sous forme de chaîne de la date formatée. C'est exactement ce que nous voulions.
Voici la même chose, mais nous utilisons DateTimeFormatter :
public static void main(String[] args) { LocalDate date = LocalDate.of(2024, 12, 31); var formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); System.out.println(formatter.format(date)); }
La console affiche ce qui suit :
31-12-2024
Mêmes étapes et même résultat, mais il y a une légère différence : DateTimeFormatter nous permet de formater uniquement les dates représentées par la classe implémentant l'interface TemporalAccessor. Par exemple, ceux-ci incluent LocalDate et LocalDateTime. SimpleDateFormat formate uniquement les objets de la classe Date.
Revenons au commentaire. L'utilisation de « Y » au lieu de « y » dans un modèle de date change-t-elle vraiment le résultat ?
Jetez un œil au code :
public static void main(String[] args) { Date date = new Date("2024/12/31"); var dateFormatter = new SimpleDateFormat("dd-MM-yyyy"); System.out.println(dateFormatter.format(date)); }
La console affiche ce qui suit :
31-12-2025
Oups. Est-ce la même chose en ce qui concerne DateTimeFormatter ?
Voici le code :
public static void main(String[] args) { LocalDate date = LocalDate.of(2024, 12, 31); var formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); System.out.println(formatter.format(date)); }
La console affiche ce qui suit :
31-12-2025
Nous avons voyagé un an dans le futur. Il est temps de voir ce qui se passe.
Ma première étape a été de consulter la documentation de la classe SimpleDateFormat. Vous trouverez ci-dessous un petit fragment du tableau qui décrit comment le modèle de date interprète les caractères alphabétiques qui nous intéressent :
Letter | Date or Time Component | Presentation | Examples |
---|---|---|---|
y | Year | Year | 1996; 96 |
Y | Week year | Year | 2009; 09 |
Une semaine par an ? Laissez-moi vous expliquer.
L'année de la semaine est une année basée sur le numéro de semaine de l'année. Qu'est-ce que cela signifie et pourquoi est-ce important ?
Dans certaines tâches, le numéro d'ordre de la semaine dans l'année est important. Pour déterminer le numéro de séquence de la semaine, nous devons décider quelle semaine considérer en premier. En effet, le passage d'une année à l'autre se traduit souvent par quelques semaines à cheval sur les deux années. Alors, comment pouvons-nous savoir à quelle année appartient cette semaine ? La norme ISO-8601 réglemente cela.
Selon cette norme, la première semaine de l'année doit répondre aux conditions suivantes :
De là, on peut déduire une règle simple : une semaine est considérée comme la première de l'année si le jeudi tombe en janvier.
Un exemple concret peut clarifier cela davantage.
Prenons la date de l'exemple, qui est le 31.12.2024. Vous trouverez ci-dessous l'extrait de calendrier de la semaine qui inclut notre date (décembre 2024-janvier 2025) :
Mo | Tu | We | Th | Fr | Sa | Su |
---|---|---|---|---|---|---|
30 | 31 | 1 | 2 | 3 | 4 | 5 |
Cette semaine est considérée comme la première semaine de 2025 car elle remplit les conditions ci-dessus (elle compte cinq jours de janvier). Donc, si nous utilisons le spécificateur « Y », nous obtenons l'année 2025.
Comme vous pouvez le deviner, le cas avec DateTimeFormatter est exactement le même.
Il est important de noter que nous pouvons voyager non seulement vers le futur mais aussi vers le passé.
Prenons une autre date, le 01.01.2027.
La première semaine de 2027 comprendra-t-elle le 1er janvier ? Encore une fois, consultons le calendrier.
Vous trouverez ci-dessous l'extrait de calendrier de la semaine qui inclut notre date (décembre 2026 – janvier 2027) :
Mo | Tu | We | Th | Fr | Sa | Su |
---|---|---|---|---|---|---|
28 | 29 | 30 | 31 | 1 | 2 | 3 |
Comme il n'y a que trois jours de janvier dans cette semaine (et qu'elle devrait être quatre la première semaine selon les exigences), elle compte comme la dernière semaine de 2026. Ainsi, la date, lorsqu'elle est formatée à l'aide du « Y » personnage, nous montrera 2026.
Voici la preuve. Jetez un oeil au code :
public static void main(String[] args) { Date date = new Date("2024/12/31"); var dateFormatter = new SimpleDateFormat("dd-MM-yyyy"); System.out.println(dateFormatter.format(date)); }
La console affiche ce qui suit :
01-01-2026
D'accord, nous avons décortiqué le problème. Nous avons également trouvé assez intéressant d'ajouter une règle de diagnostic dédiée à l'analyseur Java PVS-Studio.
La règle de diagnostic est écrite, il est donc temps de la tester.
Lors du développement de l'analyseur, l'une des étapes de test consiste à exécuter des tests de régression. Nous avons un article sur ce processus. En bref, lorsque nous ajoutons une nouvelle règle de diagnostic, nous analysons un large pool de projets open source et comparons les nouveaux rapports avec ceux de référence.
Dans le cas de cette règle de diagnostic, l'analyseur a émis de nouveaux avertissements pour plusieurs projets. Jetons un coup d'œil à eux.
Dans ce projet, les fragments de code vers lesquels pointe la règle de diagnostic sont identiques, je n'en montrerai donc qu'un.
Jetez un œil au code :
public static void main(String[] args) { LocalDate date = LocalDate.of(2024, 12, 31); var formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); System.out.println(formatter.format(date)); }
L'avertissement PVS-Studio :
V6122 L'utilisation du modèle « Y » (semaine année) a été détectée : il était probablement prévu d'utiliser « y » (année). SkeinParameters.java 246
Tout d’abord, j’ai jeté un œil à GitHub. Et s'il s'agissait vraiment d'un bug, les développeurs l'avaient déjà trouvé et résolu ? C'est exactement ce qui s'est passé. Voici un lien vers le commit, vous pouvez le consulter. Tous nos caractères « Y » (semaine année) dans le modèle ont été remplacés par « y » (année).
Vous vous demandez peut-être pourquoi les commits ont été effectués il y a relativement longtemps. Laissez-moi vous expliquer. Nos tests de régression n'ont pas pour vocation de contrôler en permanence la qualité de tel ou tel projet open source. La tâche consiste à voir comment le rapport change lorsque de nouvelles règles de diagnostic sont ajoutées : aucun ancien avertissement ne doit disparaître, aucune nouvelle erreur ne doit apparaître, car cela indiquerait que l'analyseur a un problème. Donc, le code vérifié doit être le même.
Jetons maintenant un œil au deuxième projet où la règle de diagnostic a été déclenchée.
L'avertissement PVS-Studio :
V6122 L'utilisation du modèle « Y » (semaine année) a été détectée : il était probablement prévu d'utiliser « y » (année). DépôtInfo.java 77
Le code :
public static void main(String[] args) { Date date = new Date("2024/12/31"); var dateFormatter = new SimpleDateFormat("dd-MM-YYYY"); System.out.println(dateFormatter.format(date)); }
Tout comme pour le projet précédent, je me suis précipité vers les commits pour voir ce qui se passait. Tout d'abord, il convient de noter que le champ a été déplacé vers sa classe dérivée, Repository, à la suite d'une refactorisation (voici le lien vers le commit). J'ai cherché plus loin et trouvé un commit contenant le correctif. Le caractère « Y » dans le modèle de date a été remplacé par « y » :
public static void main(String[] args) { LocalDate date = LocalDate.of(2024, 12, 31); var formatter = DateTimeFormatter.ofPattern("dd-MM-YYYY"); System.out.println(formatter.format(date)); }
Donc, c'était une erreur ici aussi.
Chez PVS-Studio, nous apprécions tout retour de la communauté. Après avoir répondu au commentaire d'un utilisateur Habr, nous avons amélioré l'analyseur Java en ajoutant quelques règles de diagnostic utiles. Donc, si vous avez des idées à partager avec nous, nous serions ravis de discuter avec vous dans la section commentaires de cet article.
À propos, la règle de diagnostic a été introduite dans la version 7.33 d'octobre. Donc, si vous souhaitez essayer notre analyseur, utilisez ce lien.
C'est tout. Terminons les choses ici. Espérons que le voyage soudain d’un an en avant (ou en arrière) ne vous surprendra pas.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!