L'API Temporal di JavaScript: un sostituto moderno di Date
JavaScript Date è rotto in modi ben noti da decenni. TC39 Temporal — Stage 4 dall'inizio del 2025, già nei browser moderni e in Node.js — separa in modo pulito gli istanti, le date da orologio da parete e le date-ora con fuso. Questa guida spiega i nuovi tipi, come si rapportano ai timestamp Unix e come migrare.
Temporal vs Date a colpo d'occhio
Il Date integrato di JavaScript è una fonte nota di bug da decenni: è mutabile, capisce solo il fuso locale e UTC, i suoi mesi sono indicizzati da zero e il suo parsing è specificato in modo lasco. Temporal è il sostituto normalizzato — Stage 4 e parte di ECMAScript 2026 — e corregge ognuno di quei problemi con tipi immutabili costruiti su misura. La tabella sotto è il contrasto generale; il resto di questa guida copre i tipi e come si rapportano ai timestamp Unix.
| Aspetto | Date (legacy) | Temporal |
|---|---|---|
| Mutabilità | Mutabile | Immutabile |
| Precisione | Millisecondi | Nanosecondi |
| Fusi orari | Solo locale + UTC | Qualsiasi fuso IANA (ZonedDateTime) |
| Indicizzazione dei mesi | Base 0 (0 = gennaio) | Base 1 (1 = gennaio) |
| Parsing | Permissivo, definito dall'implementazione | ISO 8601 / RFC 9557 rigoroso |
| Istante vs orologio da parete | Confusi in un unico tipo | Tipi separati |
Perché esiste Temporal
JavaScript Date confonde diversi concetti distinti: un istante esatto, un'ora da orologio da parete e una data-ora con fuso. Date ha anche peculiarità di parsing ben note, un unico fuso (quello dell'utente) e precisione al millisecondo. Temporal espone i concetti sottostanti come tipi separati e supporta precisione al nanosecondo, fusi IANA arbitrari e sistemi di calendario espliciti.
- Stage 4 dall'inizio del 2025; rilasciato per primo per impostazione predefinita in Firefox 139
- Ora disponibile in Chrome 144+, Firefox 139+ e Node.js 26+
- I polyfill (@js-temporal/polyfill) funzionano in qualsiasi ambiente moderno
- Progettato per coesistere con Date — esistono metodi di interoperabilità in entrambe le direzioni
I tipi essenziali di Temporal
Un piccolo insieme di tipi copre in modo pulito il problema delle date-ora. Ciascuno ha una forma di stringa canonica (ISO 8601, estesa dalla RFC 9557 per il tipo con fuso):
| Tipo | Rappresenta | Stringa di esempio |
|---|---|---|
| Temporal.Instant | Un istante esatto, come un timestamp Unix (precisione ns) | 2026-01-01T00:00:00Z |
| Temporal.ZonedDateTime | Istante + fuso IANA + calendario | 2026-01-01T09:00:00+09:00[Asia/Tokyo] |
| Temporal.PlainDateTime | Data + ora, senza fuso | 2026-01-01T09:00:00 |
| Temporal.PlainDate | Una data di calendario (es. un compleanno) | 2026-01-01 |
| Temporal.PlainTime | Un'ora da orologio da parete | 09:00:00 |
| Temporal.Duration | Una durata, consapevole delle unità | P3DT4H10M |
Lavorare con i timestamp Unix
Temporal.Instant è il tipo timestamp Unix. L'API rilasciata espone solo conversioni epoch in millisecondi e nanosecondi — i metodi precedenti fromEpochSeconds e fromEpochMicroseconds sono stati rimossi prima dello Stage 4 — quindi converti i secondi Unix moltiplicando per 1000. Usa Instant per archiviazione e trasporto, e ZonedDateTime quando ti serve una vista da orologio da parete in un fuso specifico.
- Temporal.Now.instant() — il momento esatto attuale
- Temporal.Instant.fromEpochMilliseconds(Date.now()) — da un timestamp JS in millisecondi
- Temporal.Instant.fromEpochMilliseconds(1700000000 * 1000) — da secondi Unix (× 1000)
- Temporal.Instant.fromEpochNanoseconds(1700000000000000000n) — da nanosecondi (BigInt)
- instant.epochMilliseconds e instant.epochNanoseconds — rileggere il valore epoch
- instant.toZonedDateTimeISO("America/New_York") — una vista da orologio da parete in un fuso
Fusi e DST gestiti correttamente
ZonedDateTime porta un fuso IANA, quindi le transizioni di DST, le ore di buco e le ore di sovrapposizione sono tutte gestite esplicitamente. L'opzione di disambiguazione ti lascia scegliere una politica per le ore locali ambigue, e il formato di stringa canonico è la RFC 9557 (un timestamp ISO 8601 con il fuso tra parentesi quadre).
- zdt.timeZoneId — il nome IANA (es. America/Los_Angeles)
- zdt.add({ hours: 1 }) — aritmetica consapevole del DST in termini di orologio da parete
- zdt.until(zdt2) — distanza tra due date-ora con fuso
- Opzioni di disambiguazione: "earlier", "later", "compatible" (predefinito — successivo per il buco, precedente per la sovrapposizione), "reject"
- Andata e ritorno: istante ↔ data-ora con fuso è senza perdite
Schemi di migrazione da Date
La strategia di migrazione più semplice è introdurre Temporal prima ai confini (parsing dell'input, formattazione dell'output) e spostare gradualmente la logica interna.
- Date → Instant: Temporal.Instant.fromEpochMilliseconds(date.getTime())
- Instant → Date: new Date(instant.epochMilliseconds)
- Per il codice nuovo, preferisci Temporal ovunque e converti in Date solo ai bordi dell'API
- date-fns e Luxon hanno entrambi modalità / adattatori consapevoli di Temporal
- JSON: Temporal.Instant.prototype.toJSON restituisce una stringa ISO 8601
Supporto in browser e runtime
Temporal è stato rilasciato nel 2025 e il supporto nativo è ormai ampio, ma non ancora universale. Il polyfill è la via più sicura finché i browser più vecchi e Safari stabile sono ancora in uso.
- Firefox 139+: il primo a rilasciarlo, abilitato per impostazione predefinita (maggio 2025)
- Chrome 144+: abilitato per impostazione predefinita (gennaio 2026)
- Node.js 26+: abilitato per impostazione predefinita (maggio 2026)
- Safari: disponibile in Technology Preview, non ancora in una versione stabile
- Polyfill: @js-temporal/polyfill o temporal-polyfill — stessa API, qualsiasi ambiente moderno
Riferimenti correlati
FAQ
- Temporal è un sostituto di Date?
- Sì — Temporal è progettato per sostituire del tutto Date nel codice nuovo. Date rimane nel linguaggio per retrocompatibilità, e i due interoperano tramite i millisecondi epoch.
- Come converto un timestamp Unix in Temporal?
- Usa Temporal.Instant.fromEpochMilliseconds(). Per i secondi Unix, moltiplica per 1000: Temporal.Instant.fromEpochMilliseconds(seconds * 1000). L'API rilasciata ha solo fromEpochMilliseconds e fromEpochNanoseconds — il vecchio metodo fromEpochSeconds è stato rimosso prima che Temporal raggiungesse lo Stage 4.
- Temporal supporta i nanosecondi?
- Sì. Temporal.Instant ha precisione al nanosecondo internamente ed espone epochNanoseconds come un BigInt.
- Posso usare Temporal in Node.js oggi?
- In Node.js 26+ Temporal è abilitato per impostazione predefinita. Nelle versioni precedenti di Node, installa @js-temporal/polyfill — la superficie dell'API è identica.
- Quali browser supportano Temporal?
- Firefox 139+ (maggio 2025), Chrome 144+ (gennaio 2026) e Node.js 26+ (maggio 2026) includono Temporal per impostazione predefinita. Safari lo ha in Technology Preview. Per qualsiasi cosa più vecchia, usa il @js-temporal/polyfill.
- Come gestisce Temporal il buco del DST?
- I costruttori e l'aritmetica di ZonedDateTime accettano un'opzione di disambiguazione. "compatible" (predefinito) sceglie l'istante successivo per i buchi e quello precedente per le sovrapposizioni; "reject" lancia un errore se l'ora locale è ambigua.