Pourquoi le temps en Java est une douleur (et comment la soigner)
\nChaque développeur qui a ne serait-ce qu'une fois été confronté à des tâches de globalisation d'application le sait : travailler avec les fuseaux horaires est un champ de mines. Quoi de plus simple, semble-t-il ? On prend une date, on la convertit dans un autre fuseau horaire, et voilà. Mais non. Les anciennes API comme java.util.Date et java.util.Calendar laissaient derrière elles une multitude de bugs, une confusion avec l'heure d'été et des cheveux blancs.
Heureusement, avec la sortie de Java 8, le monde a changé. Le nouveau package java.time (JSR-310) a apporté ordre et clarté. Aujourd'hui, nous allons voir comment travailler correctement avec les fuseaux horaires en Java moderne, éviter les pièges typiques et rendre le code lisible et fiable.
\nSi vous codez en Java et que votre application travaille avec des utilisateurs de différents pays, cet article est pour vous. C'est parti !
\n\nDécouverte de la nouvelle API : java.time
\nAvant de plonger dans les détails, familiarisons-nous avec les classes clés. Elles ne sont pas nombreuses et chacune a son rôle.
\n\nLocalDateTime — l'heure sans lien avec un fuseau
\nCette classe stocke la date et l'heure, mais ne tient pas compte du fuseau horaire. Elle est pratique pour enregistrer des événements qui se produisent au même endroit (par exemple, des logs sur un serveur).
\nLocalDateTime local = LocalDateTime.now();\nSystem.out.println(local); // 2025-03-15T14:30:00.123\nMais si vous essayez d'envoyer cette heure à un utilisateur à New York alors que votre serveur est à Moscou, vous créerez de la confusion. C'est pourquoi les systèmes globaux nécessitent d'autres outils.
\n\nZonedDateTime — l'heure avec toutes les informations de fuseau
\nC'est le « standard en or » pour travailler avec les fuseaux horaires en Java. Il stocke la date, l'heure et l'identifiant du fuseau horaire (ZoneId). C'est cette classe qu'il faut utiliser lorsque vous voulez savoir précisément dans quel fuseau se trouve un événement.
ZonedDateTime nowInMoscow = ZonedDateTime.now(ZoneId.of("Europe/Moscow"));\nSystem.out.println(nowInMoscow); // 2025-03-15T14:30+03:00[Europe/Moscow]\n\nOffsetDateTime — l'heure avec un décalage
\nSemblable à ZonedDateTime, mais ne stocke que le décalage par rapport à UTC (par exemple, +03:00), sans le nom de la région. Utile pour les API où seule la différence avec Greenwich compte.
\n\nInstant — un moment dans le temps en UTC
\nUn format lisible par machine. Instant est un point sur la ligne du temps, toujours en UTC. Idéal pour le stockage dans les bases de données et les échanges entre services.
Instant instant = Instant.now();\nSystem.out.println(instant); // 2025-03-15T11:30:00.123Z\n\nComment bien choisir son fuseau horaire : ZoneId
\nN'utilisez pas d'abréviations à trois lettres comme "PST" ou "CET" — elles sont ambiguës et ne tiennent pas compte de l'heure d'été. Préférez les identifiants complets de la base de données IANA (Time Zone Database).
Exemples de ZoneId corrects :
\n- \n
"Europe/Moscow"\n "America/New_York"\n "Asia/Tokyo"\n "UTC"\n
Obtenir tous les fuseaux disponibles se fait ainsi :
\nSet<String> zoneIds = ZoneId.getAvailableZoneIds();\nzoneIds.stream().sorted().limit(10).forEach(System.out::println);\n\nConversion entre fuseaux horaires : exemples pratiques
\nLa tâche la plus courante est de prendre une heure dans un fuseau et de l'afficher à l'utilisateur dans un autre. Cela se fait très simplement.
\n\nExemple 1 : Convertir l'heure de Moscou à New York
\nZonedDateTime moscowTime = ZonedDateTime.now(ZoneId.of("Europe/Moscow"));\nZonedDateTime newYorkTime = moscowTime.withZoneSameInstant(ZoneId.of("America/New_York"));\n\nSystem.out.println("Moscou : " + moscowTime);\nSystem.out.println("New York : " + newYorkTime);\nNotez la méthode withZoneSameInstant() — elle change uniquement l'affichage de l'heure, tout en conservant le moment physique.
Exemple 2 : De l'UTC à l'heure locale de l'utilisateur
\n
Blogs
Book Recommendations
Lire aussi
Test Java à partir de zéro : feuille de route pour débutant
Revue de code TypeScript : 10 erreurs qui agacent les seniors
Rédaction de documentation pour un projet PHP : de A à Z
Travail avec les dates et l'heure en C# : techniques avancées et conseils
Héritage en C++ : comment appeler correctement le constructeur de la classe de base sans casser le code