Methodology
Metodologia di data e ora
Dove la matematica delle date ingenua fallisce — e come ogni strumento /datetime/ la aggira.
By Buğra SözeriPublished
L’aritmetica di data e ora è una delle categorie di codice più tentate e più soggette a bug in qualsiasi grande codebase. I quattro strumenti sotto il nostro cluster Data & ora affrontano ciascuno un sotto-problema diverso; questa pagina spiega la matematica dietro ognuno.
Calcolatore di età — prestito consapevole del calendario
L’età in anni-mesi-giorni non è solo “oggi meno data di nascita diviso 365,25” — quella approssimazione accumula un giorno di errore ogni 4-7 anni. L’algoritmo corretto usa il prestito dal calendario:
- Calcola la differenza di anni:
now.year − birth.year. - Calcola la differenza di mesi. Se
now.month < birth.month, prendi in prestito 12 mesi dal conteggio degli anni. - Calcola la differenza di giorni. Se
now.day < birth.day, prendi in prestito giorni dal conteggio dei mesi usando la lunghezza effettiva del precedente mese del calendario.
Il passo 3 è dove il codice ingenuo fallisce. “Lunghezza del mese precedente” non è 30 o 31 — dipende da quale mese precedente (febbraio è 28 o 29, gli altri sono 30 o 31). Il nostro calcolatore di età usa new Date(year, month, 0) (che restituisce l’ultimo giorno del mese precedente) per ottenere il numero giusto ogni volta, inclusi gli anni bisestili.
Esempio pratico
Nascita: 1990-12-31. Oggi: 2026-05-14. Differenza anni: 36. Differenza mesi: −7 (maggio meno dicembre). Prendi in prestito un anno, la differenza mesi diventa 5. Differenza giorni: 14 − 31 = −17. Prendi in prestito un mese; il mese precedente è aprile, che ha 30 giorni, quindi aggiungi 30, dando una differenza di giorni di 13. Risultato: 35 anni, 4 mesi, 13 giorni.
Differenza tra date — tre unità, un denominatore
Lo strumento di differenza tra date riporta il divario tra due date in giorni, settimane e ore simultaneamente. La matematica è semplice:
giorni = (b.getTime() − a.getTime()) / 86_400_000settimane = giorni / 7 · ore = giorni × 24
La sottigliezza è nella gestione del fuso orario. Entrambe le date vengono normalizzate a mezzanotte UTC prima della sottrazione, quindi le transizioni dell’ora legale non introducono giorni frazionari. Una differenza di date che attraversa un cambio dell’ora è ancora un numero intero di giorni, come gli utenti si aspettano.
Giorni lavorativi — da lunedì a venerdì tra due date
Il contatore di giorni lavorativi usa l’algoritmo più semplice possibile: percorre ogni giorno del calendario tra le due date e incrementa un contatore quando il giorno della settimana è lunedì-venerdì.
Con ~250 giorni feriali all’anno e la costruzione di un oggetto Date che richiede mediamente ~1µs in V8 moderno, questo si completa in microsecondi per qualsiasi intervallo di date inferiore a un secolo. Non usiamo una formula closed-form perché è solo marginalmente più veloce e significativamente più difficile da leggere.
Cosa non è incluso: le festività nazionali. L’osservanza delle festività varia per paese, per anno (la maggior parte è a data fissa ma un sottoinsieme significativo si sposta con il calendario lunare o è definito come “n-esimo giorno della settimana del mese”), e per settore. Avremmo bisogno di attingere a un dataset curato per farlo in modo responsabile; lo strumento dei giorni lavorativi rimane solo-feriali intenzionalmente.
Convertitore di fuso orario — IANA tzdata + Intl.DateTimeFormat
I fusi orari sono costrutti politici, non geografici, e le loro regole cambiano. Le date di inizio dell’ora legale, gli esperimenti DST tutto l’anno, le divisioni e le unioni con la riorganizzazione dei paesi — tutto questo è catturato nel bundle IANA tzdata che viene fornito con ogni sistema operativo moderno.
Il nostro convertitore di fuso orario accede a quei dati attraverso il Intl.DateTimeFormat integrato nel browser. Non includiamo mai il nostro tzdata. Questo è importante perché:
- tzdata si aggiorna più volte all’anno quando i paesi cambiano le regole.
- Includere la nostra copia congelerebbe quei dati al momento della build.
- Il tzdata a livello di sistema operativo viene aggiornato dal vendor del sistema operativo su una cadenza di sicurezza più veloce della nostra.
L’algoritmo di conversione dell’orologio a muro
Dato “14:00 il 2026-07-04 in Europe/Istanbul, cosa è in America/Los_Angeles?”:
- Tratta “14:00 il 2026-07-04” come un timestamp UTC (chiamalo
guess). - Chiedi a Intl.DateTimeFormat: a
guess, quale offset ha Europe/Istanbul? (UTC+3.) - Aggiusta: l’istante UTC effettivo è
guess − 3 ore. - Renderizza quell’istante UTC sull’orologio a muro di Los_Angeles.
Questo gestisce le zone a mezz’ora (India, UTC+5:30) e le zone a 45 minuti (Nepal, UTC+5:45) senza casi speciali. L’unico caso che si rompe è il divario “spring forward” — le 2:30 non esistono in una zona che salta dalle 2:00 alle 3:00 — ma il calcolatore restituisce il risultato di un’ora errato piuttosto che fallire, che è comunque un’informazione utile.
Il default ISO 8601
Tutti gli input di data nell’interfaccia utente usano il formato ISO 8601 (YYYY-MM-DD). Tutti gli oggetti Date prodotti internamente sono senza fuso orario al confine e diventano consapevoli del fuso orario solo quando attraversano il convertitore di fuso orario. L’output di Intl.DateTimeFormat è localizzato nella lingua del browser dell’utente; i dati sottostanti sono sempre ISO 8601 per l’archiviazione e la serializzazione.
Frequently asked questions
- Perché non usare una libreria di date come dayjs o date-fns?
- Lo facciamo, internamente, per le parti che ne traggono beneficio — ma ogni funzione visibile in /lib/datetime/ è scritta dalle primitive. Le librerie di date scambiano dimensioni per comodità, e la nostra matematica è abbastanza semplice (e abbastanza stabile) da non valere la dipendenza.
- Il convertitore di fuso orario gestisce le date storiche?
- Entro la portata di IANA tzdata, sì. IANA contiene regole di transizione dell'ora legale risalenti approssimativamente al 1970 per la maggior parte delle zone, e prima per un sottoinsieme. Per le date pre-1970 l'offset restituito è l'offset moderno della zona, che potrebbe essere storicamente impreciso. Non usare il convertitore di fuso orario per la ricerca genealogica.
Related
- Calcolatore di età
- Differenza tra date
- Giorni lavorativi
- Convertitore fuso orario
- Pianificatore riunioni
- Convertitore timestamp Unix
- Guida ai fusi orari per team remoti
- Differenza tra date per visti
- Giorni lavorativi per la fatturazione
- Dati sui cambiamenti dell'ora legale (dati)
- Glossario: UTC
- Glossario: ISO 8601
- Glossario: Timestamp Unix
- Glossario: Fuso orario IANA
Published May 14, 2026