1 luglio 2026

Date e orari in JavaScript senza mal di testa: epoch, UTC, fusi orari e bug reali

Un modello mentale solido per evitare sfasamenti, meeting “fantasma” e sorprese con DST, offset non interi e calendari.

Gestire date e orari in JavaScript sembra banale finché l’app finisce in produzione: utenti in fusi diversi, ora legale, offset da 30/45 minuti e regole che cambiano nel tempo. In questo articolo costruisci un modello mentale pratico: cos’è davvero un timestamp (epoch), perché UTC è la lingua franca dei sistemi, come distinguere timestamp e time zone, e quale strategia adottare tra database e UI per ridurre i bug.

Gestire date e orari in JavaScript è uno di quei temi che sembrano lineari (“sono le 15:00, fine”) finché non metti l’app in mano a utenti distribuiti nel mondo. A quel punto compaiono bug che non sono edge case: eventi che slittano di ore, “domani” che non coincide per tutti, ricorrenze che saltano il 29 febbraio, timestamp mostrati nel giorno sbagliato.

L’unico modo affidabile per uscirne è costruire un modello mentale chiaro: distinguere momenti assoluti da rappresentazioni locali, capire perché esiste l’epoch time, e adottare una strategia coerente tra backend, database e frontend.

Il problema di fondo: lo stesso momento, rappresentazioni diverse

La difficoltà nasce da un fatto semplice: il tempo “civile” è relativo alla posizione.

La stessa identica istantanea (lo stesso “adesso”) viene rappresentata con orari diversi a seconda del fuso orario. In più entrano in gioco regole aggiuntive come:

  • Offset non interi: non esistono solo differenze di ore “tonde”. Ci sono fusi con +30, +45 minuti (es. India +05:30, Nepal +05:45).
  • Ora legale (DST): può spostare l’orario avanti o indietro, e non è applicata ovunque.
  • Regole che cambiano: le norme sui fusi possono essere modificate dai governi, anche con poco preavviso.
  • Calendari irregolari: mesi di diversa lunghezza, anni bisestili, 29 febbraio.

Se stai costruendo un calendario o una booking experience, questi non sono dettagli: sono requisiti.

Timestamp vs fuso orario: separa ciò che è assoluto da ciò che è “umano”

Un errore tipico è confondere timestamp e time zone.

Timestamp (momento assoluto)

Un timestamp rappresenta un istante preciso, indipendente da dove ti trovi. È un numero che identifica un momento in modo univoco.

In JavaScript, questo numero è espresso in millisecondi.

Time zone (regole di rappresentazione)

Un fuso orario è un insieme di regole “umane” per trasformare un momento assoluto in un orario leggibile in una specifica regione: include offset da UTC e spesso anche la gestione dell’ora legale.

In altre parole:

  • timestamp = “quando è successo”
  • time zone = “come lo mostro a qualcuno in un posto specifico”

Cos’è l’epoch time (e perché parte dal 1 gennaio 1970)

Per comunicare istanti in modo universale, i sistemi hanno bisogno di un riferimento comune. Questo riferimento è l’Unix epoch:

1970-01-01T00:00:00Z

Da quel momento in poi, ogni millisecondo trascorso può essere contato. Quindi:

  • 0 = 1970-01-01 00:00:00 UTC
  • 1_000_000 ≈ 11,5 giorni dopo
  • numeri molto più grandi corrispondono a date moderne (anni recenti)

Perché proprio il 1970? È in gran parte una scelta storica e pragmatica legata ai sistemi Unix: un punto di partenza semplice e condiviso.

Perché JavaScript usa i millisecondi e non i secondi?

Perché molte operazioni in ambiente web richiedono precisione sub-secondo: performance, animazioni, timeouts, misurazioni di durata. Avere l’unità base in millisecondi è comodo e coerente con questi casi.

UTC: la “lingua franca” dei sistemi

UTC (Coordinated Universal Time) è il riferimento globale. Per ragionare sui timestamp, è utile vederlo come un “orologio master” su cui tutti possono allinearsi.

Punti chiave:

  • Un timestamp è sempre riferito a UTC (perché è un numero assoluto, non “locale”).
  • I fusi orari del mondo sono definiti come offset da UTC (es. UTC−05:00, UTC+05:30, UTC+09:00).

GMT e UTC sono la stessa cosa?

Nella pratica quotidiana dello sviluppo software, puoi trattarli come equivalenti per la maggior parte dei casi applicativi. Esistono differenze storiche/tecniche, ma raramente sono rilevanti nelle UI e nella gestione standard dei timestamp.

Strategia robusta in produzione: salva in UTC, mostra in locale

Questa è una regola d’oro perché riduce drasticamente ambiguità e bug:

  1. Persisti sempre in UTC (timestamp/epoch) nel database.
  2. Converti in locale solo al momento della visualizzazione in UI, usando il fuso dell’utente (o quello richiesto dal contesto).

Perché funziona?

  • Il database conserva un “momento assoluto” unico.
  • Ogni client può renderlo correttamente secondo le proprie regole locali.

Esempio concettuale:

  • Salvi 1720000000000 (epoch ms) nel DB.
  • Un utente in India lo vede come un certo orario in IST.
  • Un utente in Francia lo vede come un altro orario in CET/CEST.
  • È lo stesso evento, rappresentato correttamente per entrambi.

Il limite storico di JavaScript: poche certezze sui fusi

Qui sta molta della frustrazione: l’ecosistema JavaScript “classico” tende a oscillare tra due poli comodi ma insufficienti:

  • UTC
  • il fuso orario locale dell’ambiente (browser o runtime)

Appena devi gestire esplicitamente fusi diversi da quello locale (es. mostrare l’orario “di New York” a un utente in Italia), serve una strategia più attenta: formattazione corretta, gestione delle regole del fuso (incluso DST), e dati aggiornati.

Sintesi operativa

Se lavori su funzionalità con date/orari (calendari, prenotazioni, scadenze, timeline), le basi che ti evitano problemi sono:

  • pensa in termini di timestamp (assoluto) + time zone (rappresentazione)
  • tratta l’epoch come la tua unità di scambio universale
  • salva in UTC, mostra in locale
  • ricordati che offset e DST non sono “dettagli”: sono parte del dominio

Il risultato è un’app più prevedibile: gli eventi non “cambiano giorno” a seconda di chi guarda, e le decisioni su che cosa mostrare (e in quale fuso) diventano esplicite invece che accidentali. In produzione, è la differenza tra un calendario affidabile e un generatore di ticket.