Millisecondes vs secondes : la confusion d'unités qui casse chaque appli
Le bug de timestamp le plus courant est de passer des millisecondes là où des secondes sont attendues, ou l'inverse. Apprenez la règle des 10 contre 13 chiffres, les valeurs par défaut des langages, les implications en base et les modèles de conversion sûrs.
Pourquoi il existe deux standards
Le temps Unix a d'abord été défini en secondes : un entier semblait naturel pour un système qui s'incrémentait à chaque tic d'horloge. L'objet Date de JavaScript, introduit en 1995, a choisi les millisecondes pour gérer la temporisation d'événements sous la seconde dans le navigateur. Beaucoup de bases et de langages backend ont gardé les secondes Unix par défaut. Aujourd'hui, les deux standards coexistent dans tout code qui franchit la frontière JavaScript-serveur, d'où le fait qu'une valeur peut sembler valide tout en représentant une date à des dizaines de milliers d'années.
Quelle unité chaque langage utilise
La façon la plus sûre de retenir le partage : les API Date du navigateur veulent en général des millisecondes, les API serveur de style Unix exposent en général des secondes, et les bibliothèques de temps récentes proposent souvent les deux. Ne déduisez pas l'unité du seul langage en lisant la doc d'une API tierce ; vérifiez la description du champ et les exemples.
- Milliseconds: JavaScript Date.now(), Java System.currentTimeMillis(), Java Instant.toEpochMilli(), .NET ToUnixTimeMilliseconds()
- Seconds: Python time.time() (float), PHP time(), Go time.Now().Unix(), Ruby Time.now.to_i, C time(NULL), PostgreSQL EXTRACT(EPOCH)
- Both: Rust — duration.as_secs() for seconds, duration.as_millis() for milliseconds
- Python note: time.time() returns a float, so milliseconds are available as int(time.time() * 1000)
Détecter l'unité à partir de la valeur
Une heuristique fiable pour les dates modernes : un nombre à 10 chiffres correspond à des secondes ; à 13 chiffres, à des millisecondes. Les secondes Unix actuelles sont autour de 1,7–2,1 milliards (10 chiffres) et n'atteindront pas 13 chiffres avant l'an 33658. Les millisecondes Unix actuelles ont déjà 13 chiffres. L'heuristique est la plus fiable des années 2000 aux quelques milliers d'années à venir ; pour les dates historiques, négatives ou les fixtures de test compactes, utilisez des unités explicites plutôt que de deviner.
- valeur à 10 chiffres → secondes (ex. 1700000000 = 2023-11-14 UTC)
- valeur à 13 chiffres → millisecondes (ex. 1700000000000 = 2023-11-14 UTC)
- valeur à 16 chiffres → microsecondes (diviser par 1,000,000 pour des secondes)
- valeur négative → date avant le 1er janvier 1970 (secondes ou millisecondes)
Modèles de conversion sûrs
La conversion elle-même est une arithmétique simple ; le difficile est de choisir où elle doit se faire. Convertissez à la frontière du système, nommez la valeur convertie et évitez de faire passer des nombres bruts ambigus à travers plusieurs couches.
- Seconds to milliseconds: seconds * 1000
- Milliseconds to whole seconds — JavaScript: Math.floor(ms / 1000)
- Milliseconds to whole seconds — Python: ms // 1000
- Milliseconds to whole seconds — Go: ms / 1000 (integer division)
- Universal guard in JavaScript: const toMs = ts => ts < 1e11 ? ts * 1000 : ts
Comment les bugs d'unité apparaissent en production
Un bug secondes-vs-millisecondes survit souvent à la validation car les deux valeurs ne sont que des nombres. Il apparaît plus tard comme une date impossible : janvier 1970 en JavaScript quand des secondes ont été traitées comme des millisecondes, ou une année très lointaine quand un backend a traité des millisecondes comme des secondes.
- Date de 1970 dans l'UI JavaScript → des secondes ont été passées à new Date() sans multiplier par 1000
- Année 50000+ en Python, Go ou PHP → des millisecondes ont été passées à une API attendant des secondes
- Jetons expirés qui n'expirent jamais → timestamp d'expiration stocké dans la mauvaise unité
- Entrées de cache qui disparaissent aussitôt → millisecondes divisées deux fois ou secondes multipliées deux fois
- Graphiques analytics aux plages vides → les bornes de requête utilisent une unité différente des timestamps d'événements stockés
Conventions de nommage pour les API et les bases
Une petite convention de nommage évite la plupart de ces bugs. Ne publiez jamais un champ d'API nommé timestamp à moins que la doc ne soit exceptionnellement claire. Préférez des noms de champ qui incluent le sens et l'unité.
- createdAtMs — Unix milliseconds, best for JavaScript clients
- createdAtSeconds — Unix seconds, common for backend services
- createdAtIso — ISO 8601 string, useful for human-readable API responses
- expiresAtUnixSeconds — explicit enough for auth tokens and signed URLs
- event_time TIMESTAMPTZ — native database time, with conversion handled by the database
FAQ millisecondes vs secondes
- Un timestamp à 13 chiffres est-il toujours en millisecondes ?
- Pour les timestamps Unix réels modernes, oui : 13 chiffres signifient en général des millisecondes. Des timestamps en secondes très lointains peuvent aussi atteindre 13 chiffres, donc les systèmes critiques devraient porter des métadonnées d'unité explicites.
- Dois-je stocker des secondes ou des millisecondes ?
- Stockez l'unité que votre système utilise naturellement, mais documentez-la et restez cohérent. Les systèmes très orientés JavaScript utilisent souvent des millisecondes ; les backends de style Unix et beaucoup de bases utilisent souvent des secondes ou des colonnes datetime natives.
- Pourquoi utiliser Math.floor(ms / 1000) plutôt que ms / 1000 ?
- Les secondes Unix sont en général des secondes entières. Math.floor supprime la partie fractionnaire pour que les API attendant des secondes entières ne reçoivent pas de décimale.
- Comment convertir des millisecondes en secondes ?
- Divisez par 1000 et supprimez la fraction : Math.floor(ms / 1000) en JavaScript, ms // 1000 en Python, ou ms / 1000 en division entière en Go. Pour l'inverse, multipliez les secondes par 1000.