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 UTC1_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:
- Persisti sempre in UTC (timestamp/epoch) nel database.
- 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.