Formattazione di date corretta per fuso in JavaScript senza librerie
L'Intl.DateTimeFormat integrato di JavaScript gestisce la formattazione dei fusi IANA senza moment.js o date-fns. Impara le opzioni timeZone esplicite, la visualizzazione sicura rispetto all'ora legale, formatToParts, i limiti della conversione dell'orologio e quando Temporal o una libreria di fusi è ancora utile.
Perché Date non ha una proprietà di fuso orario
Un Date di JavaScript è sempre un conteggio di millisecondi UTC. Nessun fuso è memorizzato dentro l'oggetto. Quando chiami .toString() o .toLocaleString() senza opzioni, JavaScript usa il fuso locale del runtime dal sistema operativo. Lo stesso codice produce output diversi su un server a New York e su un portatile a Tokyo, anche se il timestamp sottostante è identico.
Formattare con Intl.DateTimeFormat
Intl.DateTimeFormat è l'API integrata per la formattazione consapevole di locale e fuso. Supporta gli identificatori di fuso IANA, gestisce automaticamente le transizioni dell'ora legale ed è disponibile nei browser moderni e in Node.js. La chiave è passare l'opzione timeZone esplicitamente invece di affidarsi al default del runtime.
- new Intl.DateTimeFormat('en-US', { timeZone: 'America/New_York', dateStyle: 'full', timeStyle: 'long' }).format(date)
- date.toLocaleString('en-GB', { timeZone: 'Europe/London', hour12: false })
- date.toLocaleString('ja-JP', { timeZone: 'Asia/Tokyo' })
- new Intl.DateTimeFormat('en-US', { timeZone: 'UTC', hour12: false }).format(date)
Estrarre singole parti con formatToParts
Usa formatToParts() per ottenere i singoli componenti della data come oggetti {type, value} e costruire stringhe di data personalizzate. È meglio che dividere una stringa di data localizzata perché punteggiatura, ordine e scritture variano per locale.
- const parts = new Intl.DateTimeFormat('en-US', { timeZone: 'America/Chicago', year: 'numeric', month: '2-digit', day: '2-digit' }).formatToParts(date)
- parts.find(p => p.type === 'year').value → '2023'
- parts.find(p => p.type === 'month').value → '11'
- Object.fromEntries(parts.map(p => [p.type, p.value])) → { year, month, day, hour, minute, second }
Convertire l'ora dell'orologio in UTC (la direzione difficile)
Passare da un'ora dell'orologio in un dato fuso a UTC è più difficile con la classica API Date. Formattare un istante in America/New_York è facile; costruire l'istante rappresentato da 2026-03-08 02:30 in America/New_York non lo è, perché quell'ora locale può essere saltata o ripetuta durante le transizioni dell'ora legale.
- Temporal ha raggiunto lo Stage 4 nel 2026, ma il supporto nativo dei browser non è ancora universale
- Per l'uso in produzione su tutti i browser oggi, il polyfill di Temporal o date-fns-tz toDate() restano scelte pratiche
- Evita l'aritmetica manuale di offset UTC — le transizioni dell'ora legale avvengono a orari locali diversi in anni diversi
- Il zonedToEpochMs() di questo sito usa una correzione di offset in una iterazione — vedi src/timeUtils.ts
Scegliere l'identificatore di fuso corretto
Usa nomi di fuso IANA come America/New_York, Europe/London, Asia/Tokyo o UTC. Evita offset fissi come UTC-5 per l'ora rivolta all'utente perché gli offset cambiano con l'ora legale. America/New_York può essere UTC-5 a gennaio e UTC-4 a luglio; il nome IANA consente alla piattaforma di applicare la regola storica corretta per la data selezionata.
- Bene: America/Los_Angeles — include regole di ora legale storiche e future
- Bene: Europe/Berlin — gestisce automaticamente l'ora legale dell'Europa centrale
- Bene: Asia/Shanghai — visualizzazione stabile UTC+8 senza ora legale
- Usa UTC per log, archiviazione API, timestamp di database e confronto tra regioni
- Usa il fuso IANA dell'utente per la visualizzazione finale nella UI del prodotto
FAQ sulla formattazione dei fusi
- JavaScript può formattare una data in un altro fuso senza una libreria?
- Sì. Usa Intl.DateTimeFormat o toLocaleString con un'opzione timeZone, come America/New_York o Asia/Tokyo.
- Intl.DateTimeFormat gestisce l'ora legale?
- Sì. Quando usi un identificatore di fuso IANA, il runtime applica l'offset corretto per quel fuso e quella data.
- Devo memorizzare offset di fuso o nomi di fuso?
- Memorizza UTC per gli istanti degli eventi. Se ti serve il contesto locale dell'utente, memorizza un nome di fuso IANA come America/New_York, non solo un offset numerico.
- Come ottengo il fuso dell'utente in JavaScript?
- Usa Intl.DateTimeFormat().resolvedOptions().timeZone, che restituisce un nome IANA come America/New_York. Memorizza quel nome, non un offset numerico, quando devi ricostruire in seguito l'ora locale dell'utente.