1927 : Ce moment précis où le temps a reculé
\n\nImaginez : vous écrivez en Java un simple script pour calculer la différence entre deux dates en millisecondes. Vous prenez l'année 1927, vous soustrayez une valeur à une autre — et au lieu de 3600 secondes (une heure), vous obtenez un nombre étrange. Vous vérifiez votre code, vous cherchez sur Google, vous trouvez la légendaire question sur StackOverflow avec des milliers de vues. Et vous comprenez : vous n'êtes pas seul.
\n\nCe bug est un véritable artefact historique qui effraie encore les débutants. Dans cet article, nous allons analyser pourquoi la soustraction des temps epoch-milli en 1927 donne un résultat étrange, le montrer avec des exemples concrets de code Java et, surtout, donner des moyens concrets d'éviter ce piège. Si vous travaillez avec des données historiques ou si vous voulez simplement écrire du code fiable, ces informations sont pour vous.
\n\nLe cœur du problème : La magie du 31 décembre 1927
\n\nAllons droit au code. Voici un exemple classique qui fait perdre la tête :
\n\nimport java.util.TimeZone;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\npublic class StrangeDateDifference {\n public static void main(String[] args) throws Exception {\n TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai");\n SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");\n sdf.setTimeZone(tz);\n\n Date date1 = sdf.parse("1927-12-31 23:54:07");\n Date date2 = sdf.parse("1927-12-31 23:54:08");\n\n long diff = date2.getTime() - date1.getTime();\n System.out.println("Différence en millisecondes : " + diff);\n // On attend 1000, mais on obtient...\n }\n}\n\nVous exécutez — et au lieu de 1000 millisecondes (1 seconde), vous voyez 353 ? Ou même un nombre négatif ? Félicitations, vous avez rencontré l'erreur de soustraction de dates de 1927.
\n\nLa cause n'est pas un bug de Java (bien qu'il y en ait aussi, mais nous y reviendrons). La cause est un changement historique de fuseau horaire. Le 31 décembre 1927 à Shanghai (Asia/Shanghai), il s'est produit quelque chose d'étrange : à 23:54:08, l'heure locale a été reculée de 5 minutes et 52 secondes. En réalité, la seconde n'a pas duré 1000 ms, mais seulement 353 ms. Java reproduit fidèlement ce fait historique, mais pour le développeur, cela ressemble à de la magie.
\n\nTop des erreurs commises par les développeurs
\n\n1. Confiance aveugle dans les anciennes API (java.util.Date et SimpleDateFormat)
\n\nLa première et la plus courante des erreurs est l'utilisation des classes obsolètes java.util.Date et SimpleDateFormat. Elles sont non seulement peu pratiques, mais contiennent également des surprises cachées, surtout lorsqu'on travaille avec des dates historiques.
Comment l'éviter : Utilisez java.time (Java 8+). Par exemple :
import java.time.LocalDateTime;\nimport java.time.ZoneId;\nimport java.time.ZonedDateTime;\nimport java.time.format.DateTimeFormatter;\n\npublic class SafeDateDifference {\n public static void main(String[] args) {\n DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");\n ZoneId zone = ZoneId.of("Asia/Shanghai");\n\n LocalDateTime ldt1 = LocalDateTime.parse("1927-12-31 23:54:07", formatter);\n LocalDateTime ldt2 = LocalDateTime.parse("1927-12-31 23:54:08", formatter);\n\n ZonedDateTime zdt1 = ldt1.atZone(zone);\n ZonedDateTime zdt2 = ldt2.atZone(zone);\n\n long diff = zdt2.toInstant().toEpochMilli() - zdt1.toInstant().toEpochMilli();\n System.out.println("Différence en millisecondes : " + diff);\n // Vous obtiendrez toujours un nombre étrange, mais au moins vous saurez pourquoi !\n }\n}\n\n2. Ignorer les changements historiques des fuseaux horaires
\n\nBeaucoup pensent que les fuseaux horaires ne sont qu'un simple décalage fixe par rapport à UTC. Mais en réalité, ils ont changé des dizaines de fois au cours des 100 dernières années.