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.