Skip to content

Methodology

Metodologia di data e ora

Dove la matematica delle date ingenua fallisce — e come ogni strumento /datetime/ la aggira.

By Published

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:

  1. Calcola la differenza di anni: now.year − birth.year.
  2. Calcola la differenza di mesi. Se now.month < birth.month, prendi in prestito 12 mesi dal conteggio degli anni.
  3. 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_000
settimane = 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?”:

  1. Tratta “14:00 il 2026-07-04” come un timestamp UTC (chiamalo guess).
  2. Chiedi a Intl.DateTimeFormat: a guess, quale offset ha Europe/Istanbul? (UTC+3.)
  3. Aggiusta: l’istante UTC effettivo è guess − 3 ore.
  4. 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

Published May 14, 2026