Vai al contenuto
LeedyBox
Sostieni

I timestamp Unix spiegati

Un timestamp Unix è un unico numero che indica un istante nel tempo. È facile da memorizzare e da confrontare, ma unità di misura, fusi orari e formati testuali causano molti errori di conversione.

Che cos’è il tempo Unix

Il tempo Unix (chiamato anche epoch time o tempo POSIX) conta i secondi trascorsi da 1970-01-01 00:00:00 UTC, l’epoch Unix. 0 è l’epoch stessa, 1700000000 corrisponde a 2023-11-14 22:13:20 UTC e i valori negativi indicano istanti precedenti al 1970: -1 è 1969-12-31 23:59:59 UTC.

Il numero non contiene alcun fuso orario: descrive lo stesso istante ovunque, il che lo rende pratico per memorizzare, ordinare e confrontare eventi.

Il tempo Unix ignora i secondi intercalari: ogni giorno ha esattamente 86.400 secondi. Quando a UTC viene aggiunto un secondo intercalare, i sistemi ripetono un secondo oppure lo distribuiscono su un periodo più lungo («smearing»), quindi una differenza calcolata a cavallo di un secondo intercalare risulta più corta di un secondo rispetto al tempo fisicamente trascorso.

Secondi, millisecondi, microsecondi o nanosecondi?

Molti sistemi contano in unità più piccole, e il numero non dice quale. Lo stesso istante può comparire come quattro numeri molto diversi:

Unità 2023-11-14 22:13:20 UTC Cifre (2001–2286) Si trova spesso in
Secondi 1700000000 10 date +%s, molte API, claim exp dei JWT
Millisecondi 1700000000000 13 Date.now() di JavaScript, System.currentTimeMillis() di Java
Microsecondi 1700000000000000 16 Alcuni database e sistemi di logging
Nanosecondi 1700000000000000000 19 UnixNano() di Go, time.time_ns() di Python

Contare le cifre è il controllo più rapido per le date attuali. Il convertitore di LeedyBox usa la stessa idea: i valori fino a 1011 vengono letti come secondi, fino a 1014 come millisecondi, fino a 1017 come microsecondi e i valori più grandi come nanosecondi. Questa regola empirica non funziona per date molto lontane da oggi, quindi controlla l’unità quando un risultato sembra strano.

Conta anche la precisione. I numeri di JavaScript rappresentano esattamente gli interi solo fino a 253 (circa 9 × 1015), quindi un valore in nanosecondi come 1700000000123456789 perde le ultime cifre quando viene letto come numero normale. Conserva questi valori come stringhe o usa BigInt; il convertitore lo fa internamente. Per leggere il claim exp di un token, decodificalo con lo strumento Base64 / URL / JWT.

Fusi orari e ora legale

Per mostrare un timestamp come data e ora serve un fuso orario. UTC è il riferimento; l’ora locale aggiunge uno scostamento, ad esempio +09:00 a Seul o −05:00 a New York in inverno.

Preferisci i nomi di fuso orario IANA come Asia/Seoul o America/New_York agli scostamenti fissi e alle abbreviazioni: un nome porta con sé la storia del fuso e le regole dell’ora legale, mentre un’abbreviazione come CST indica più fusi diversi. Le regole provengono dal database dei fusi orari, che cambia diverse volte all’anno, e browser, sistemi operativi e linguaggi ne includono copie proprie, quindi i risultati per date passate o future possono differire.

L’ora legale crea due casi scomodi quando converti un’ora locale in un timestamp:

  • Salto: quando gli orologi vanno avanti, alcune ore locali non esistono. In America/New_York, l’orario 2026-03-08 02:30 viene saltato perché gli orologi passano direttamente dalle 02:00 alle 03:00.
  • Sovrapposizione: quando gli orologi tornano indietro, alcune ore locali si presentano due volte. L’orario 2026-11-01 01:30 si verifica una volta in EDT (UTC−04:00) e di nuovo un’ora dopo in EST (UTC−05:00).

Le librerie risolvono questi casi in modi diversi. Il convertitore di LeedyBox usa l’orario valido successivo in caso di salto (qui le 03:30) e la prima occorrenza in caso di sovrapposizione, e lo spiega in una nota. I job pianificati affrontano lo stesso problema; vedi Come leggere le espressioni cron.

ISO 8601, RFC 3339 e date HTTP

Quando un istante deve essere leggibile, scrivilo in ISO 8601 o nel suo profilo più rigoroso per Internet, RFC 3339:

2023-11-14T22:13:20Z
2023-11-15T07:13:20+09:00
2023-11-14T22:13:20.500Z

Z significa UTC. Con Z o con uno scostamento la stringa è univoca. Una stringa senza nessuno dei due, come 2023-11-14T22:13:20, è un’ora locale in un fuso sconosciuto, e i parser non concordano su come interpretarla.

Le intestazioni HTTP come Last-Modified ed Expires usano un formato più vecchio, derivato dal formato delle date delle email (RFC 2822, oggi RFC 5322) e scritto in GMT: Tue, 14 Nov 2023 22:13:20 GMT.

Il problema dell’anno 2038

Molti sistemi meno recenti memorizzano il tempo Unix in un intero con segno a 32 bit. Il suo valore massimo, 2147483647, corrisponde a 2038-01-19 03:14:07 UTC. Un secondo dopo il contatore va in overflow e passa a -2147483648, che si legge come 1901-12-13 20:45:52 UTC. I sistemi operativi e i linguaggi attuali usano per lo più valori temporali a 64 bit, che coprono centinaia di miliardi di anni, ma i campi a 32 bit compaiono ancora in dispositivi embedded, formati di file, colonne di database e protocolli di rete. Se il tuo codice o i tuoi dati memorizzano i secondi in 32 bit, pianifica il passaggio per tempo e prova fin da ora le date successive al 2038.

Timestamp nel codice e nei database

JavaScript lavora in millisecondi:

Math.floor(Date.now() / 1000);                  // tempo Unix attuale in secondi
new Date(1700000000 * 1000).toISOString();      // "2023-11-14T22:13:20.000Z"
Date.parse("2026-10-03T09:00:00+09:00") / 1000; // 1790985600

In Python time.time() restituisce i secondi come numero in virgola mobile. Passa tz=timezone.utc, altrimenti fromtimestamp() restituisce l’ora locale del computer senza fuso orario:

import time
from datetime import datetime, timezone

int(time.time())                                     # secondi
datetime.fromtimestamp(1700000000, tz=timezone.utc)  # 2023-11-14 22:13:20+00:00
datetime.fromisoformat("2026-10-03T09:00:00+09:00").timestamp()  # 1790985600.0

In SQL le funzioni variano da un database all’altro:

-- PostgreSQL
SELECT extract(epoch FROM now());   -- secondi, con parte frazionaria
SELECT to_timestamp(1700000000);    -- timestamp with time zone
-- MySQL
SELECT UNIX_TIMESTAMP();
SELECT FROM_UNIXTIME(1700000000);   -- nel fuso orario della sessione

Per la memorizzazione, alcune abitudini prevengono la maggior parte dei problemi:

  • Memorizza in UTC gli istanti già avvenuti, in una colonna di tipo timestamp con fuso orario oppure come intero a 64 bit la cui unità fa parte del nome della colonna, ad esempio created_at_ms.
  • Memorizza gli eventi locali futuri, come una riunione alle 09:00 a Seul, come data e ora locali più il nome del fuso IANA, e calcola il timestamp quando serve, così un successivo cambio delle regole non sposta la riunione.
  • Non mescolare unità diverse nella stessa colonna: un’unità sbagliata produce un errore di un fattore 1.000 o più.

Domande frequenti

Perché il mio timestamp viene convertito in una data del 1970?

Probabilmente il valore è stato letto nell’unità sbagliata: i secondi letti come millisecondi finiscono nel gennaio 1970, mentre i millisecondi letti come secondi finiscono decine di migliaia di anni nel futuro. Conta le cifre o scegli l’unità nel convertitore.

Un timestamp Unix dipende dal mio fuso orario?

No. Conta i secondi a partire da un istante fisso in UTC. Solo la data e l’ora con cui viene mostrato dipendono dal fuso orario.

Il tempo Unix può rappresentare un secondo intercalare?

No. Il tempo Unix considera ogni giorno lungo 86.400 secondi, quindi un orario UTC come 23:59:60 non ha un timestamp proprio.