L'API Temporal de JavaScript : un remplaçant moderne de Date
JavaScript Date est cassé de façons bien connues depuis des décennies. TC39 Temporal — Stage 4 depuis début 2025, livré dans les navigateurs modernes et Node.js — sépare proprement les instants, les dates d'horloge murale et les date-heures zonées. Ce guide explique les nouveaux types, leur correspondance avec les timestamps Unix, et comment migrer.
Temporal vs Date en un coup d'œil
Le Date intégré de JavaScript est une source de bugs connue depuis des décennies : il est mutable, il ne comprend que le fuseau local et UTC, ses mois sont indexés à zéro et son parsing est vaguement spécifié. Temporal est le remplaçant normalisé — Stage 4 et partie d'ECMAScript 2026 — et corrige chacun de ces problèmes avec des types immuables conçus à dessein. Le tableau ci-dessous est le contraste général ; le reste de ce guide couvre les types et leur correspondance avec les timestamps Unix.
| Aspect | Date (ancien) | Temporal |
|---|---|---|
| Mutabilité | Mutable | Immuable |
| Précision | Millisecondes | Nanosecondes |
| Fuseaux horaires | Local + UTC seulement | Tout fuseau IANA (ZonedDateTime) |
| Indexation des mois | Base 0 (0 = janvier) | Base 1 (1 = janvier) |
| Parsing | Permissif, défini par l'implémentation | ISO 8601 / RFC 9557 strict |
| Instant vs horloge murale | Confondus en un seul type | Types séparés |
Pourquoi Temporal existe
JavaScript Date confond plusieurs concepts distincts : un instant exact, une heure d'horloge murale et une date-heure zonée. Date a aussi des bizarreries de parsing bien connues, un seul fuseau (celui de l'utilisateur) et une précision milliseconde. Temporal expose les concepts sous-jacents comme des types séparés et prend en charge la précision nanoseconde, des fuseaux IANA arbitraires et des systèmes de calendrier explicites.
- Stage 4 depuis début 2025 ; livré en premier par défaut dans Firefox 139
- Désormais disponible dans Chrome 144+, Firefox 139+ et Node.js 26+
- Les polyfills (@js-temporal/polyfill) fonctionnent dans tout environnement moderne
- Conçu pour coexister avec Date — des méthodes d'interop existent dans les deux sens
Les types Temporal essentiels
Un petit ensemble de types couvre proprement le problème des date-heures. Chacun a une forme de chaîne canonique (ISO 8601, étendu par RFC 9557 pour le type zoné) :
| Type | Représente | Exemple de chaîne |
|---|---|---|
| Temporal.Instant | Un instant exact, comme un timestamp Unix (précision ns) | 2026-01-01T00:00:00Z |
| Temporal.ZonedDateTime | Instant + fuseau IANA + calendrier | 2026-01-01T09:00:00+09:00[Asia/Tokyo] |
| Temporal.PlainDateTime | Date + heure, sans fuseau | 2026-01-01T09:00:00 |
| Temporal.PlainDate | Une date calendaire (p. ex. un anniversaire) | 2026-01-01 |
| Temporal.PlainTime | Une heure d'horloge murale | 09:00:00 |
| Temporal.Duration | Une durée, consciente des unités | P3DT4H10M |
Travailler avec les timestamps Unix
Temporal.Instant est le type timestamp Unix. L'API livrée n'expose que les conversions epoch en millisecondes et nanosecondes — les méthodes antérieures fromEpochSeconds et fromEpochMicroseconds ont été retirées avant le Stage 4 — convertis donc les secondes Unix en multipliant par 1000. Utilise Instant pour le stockage et le transport, et ZonedDateTime quand tu as besoin d'une vue d'horloge murale dans un fuseau précis.
- Temporal.Now.instant() — le moment exact actuel
- Temporal.Instant.fromEpochMilliseconds(Date.now()) — depuis un timestamp JS en millisecondes
- Temporal.Instant.fromEpochMilliseconds(1700000000 * 1000) — depuis des secondes Unix (× 1000)
- Temporal.Instant.fromEpochNanoseconds(1700000000000000000n) — depuis des nanosecondes (BigInt)
- instant.epochMilliseconds et instant.epochNanoseconds — relire la valeur epoch
- instant.toZonedDateTimeISO("America/New_York") — une vue d'horloge murale dans un fuseau
Fuseaux et DST gérés correctement
ZonedDateTime porte un fuseau IANA, donc les transitions DST, les heures de trou et les heures de chevauchement sont toutes gérées explicitement. L'option de désambiguïsation te laisse choisir une politique pour les heures locales ambiguës, et le format de chaîne canonique est RFC 9557 (un timestamp ISO 8601 avec un fuseau entre crochets).
- zdt.timeZoneId — le nom IANA (p. ex. America/Los_Angeles)
- zdt.add({ hours: 1 }) — arithmétique consciente du DST en termes d'horloge murale
- zdt.until(zdt2) — distance entre deux date-heures zonées
- Options de désambiguïsation : "earlier", "later", "compatible" (par défaut — ultérieur pour le trou, antérieur pour le chevauchement), "reject"
- Aller-retour : instant ↔ date-heure zonée est sans perte
Schémas de migration depuis Date
La stratégie de migration la plus simple est d'introduire Temporal d'abord aux frontières (parsing des entrées, formatage des sorties) et de déplacer progressivement la logique interne.
- Date → Instant : Temporal.Instant.fromEpochMilliseconds(date.getTime())
- Instant → Date : new Date(instant.epochMilliseconds)
- Pour le nouveau code, préférer Temporal partout et ne convertir en Date qu'aux bords de l'API
- date-fns et Luxon ont tous deux des modes / adaptateurs conscients de Temporal
- JSON : Temporal.Instant.prototype.toJSON renvoie une chaîne ISO 8601
Prise en charge par navigateurs et runtimes
Temporal a été livré en 2025 et la prise en charge native est désormais large, mais pas encore universelle. Le polyfill est la voie la plus sûre tant que les anciens navigateurs et Safari stable sont encore en service.
- Firefox 139+ : le premier à le livrer, activé par défaut (mai 2025)
- Chrome 144+ : activé par défaut (janvier 2026)
- Node.js 26+ : activé par défaut (mai 2026)
- Safari : disponible en Technology Preview, pas encore dans une version stable
- Polyfill : @js-temporal/polyfill ou temporal-polyfill — même API, tout environnement moderne
Références associées
FAQ
- Temporal est-il un remplaçant de Date ?
- Oui — Temporal est conçu pour remplacer entièrement Date dans le nouveau code. Date reste dans le langage pour la rétrocompatibilité, et les deux interopèrent via les millisecondes epoch.
- Comment convertir un timestamp Unix en Temporal ?
- Utilise Temporal.Instant.fromEpochMilliseconds(). Pour des secondes Unix, multiplie par 1000 : Temporal.Instant.fromEpochMilliseconds(seconds * 1000). L'API livrée n'a que fromEpochMilliseconds et fromEpochNanoseconds — l'ancienne méthode fromEpochSeconds a été retirée avant que Temporal atteigne le Stage 4.
- Temporal prend-il en charge les nanosecondes ?
- Oui. Temporal.Instant a une précision nanoseconde en interne et expose epochNanoseconds sous forme de BigInt.
- Puis-je utiliser Temporal dans Node.js aujourd'hui ?
- Dans Node.js 26+, Temporal est activé par défaut. Dans les versions antérieures de Node, installe @js-temporal/polyfill — la surface de l'API est identique.
- Quels navigateurs prennent en charge Temporal ?
- Firefox 139+ (mai 2025), Chrome 144+ (janvier 2026) et Node.js 26+ (mai 2026) livrent Temporal par défaut. Safari l'a en Technology Preview. Pour tout ce qui est plus ancien, utilise le @js-temporal/polyfill.
- Comment Temporal gère-t-il le trou du DST ?
- Les constructeurs et l'arithmétique de ZonedDateTime acceptent une option de désambiguïsation. "compatible" (par défaut) choisit l'instant ultérieur pour les trous et l'antérieur pour les chevauchements ; "reject" lève une erreur si l'heure locale est ambiguë.