SQLite non ha davvero un tipo per le date
Questo spiazza chiunque arrivi da Postgres o MySQL. SQLite ha cinque classi di archiviazione, NULL, INTEGER, REAL, TEXT, BLOB, e basta. Non esiste DATE, né DATETIME, né TIMESTAMP. Puoi scrivere created_at DATETIME nel tuo CREATE TABLE, e SQLite lo accetta, ma salva il valore come semplice testo o come numero.
Quello che SQLite ti dà è un insieme di funzioni che capiscono tre formati convenzionali:
- Testo ISO 8601:
'2026-04-23','2026-04-23 10:15:00','2026-04-23T10:15:00.123Z'. - Timestamp Unix: secondi dal 1970-01-01 UTC, salvati come intero.
- Numero del giorno giuliano: giorni frazionari dal 4714 a.C., salvati come real.
Scegline uno e resta su quello. Il testo ISO 8601 è il più leggibile e si ordina correttamente come stringa, ed è per questo che è il formato predefinito.
Quattro modi per chiedere "adesso": data in testo, data e ora in testo, secondi Unix, giorno giuliano. Descrivono tutti lo stesso istante.
Le cinque funzioni per le date
SQLite ti dà cinque funzioni integrate che coprono quasi tutto:
date(time, ...): restituisceYYYY-MM-DD.time(time, ...): restituisceHH:MM:SS.datetime(time, ...): restituisceYYYY-MM-DD HH:MM:SS.julianday(time, ...): restituisce un real (ottimo per le differenze).strftime(format, time, ...): restituisce una stringa con un formato personalizzato.
Ognuna prende un valore temporale come primo argomento, poi un numero qualsiasi di stringhe modificatore.
Nota 'unixepoch': è il modo per dire alle funzioni per le date che l'intero in ingresso è un timestamp Unix e non un giorno giuliano. Senza, SQLite presume che il numero sia giuliano.
strftime: formati di data personalizzati
strftime è il cavallo da tiro. Usa gli stessi codici % che conosci da C o Python:
I codici che userai più spesso:
%Y: anno a quattro cifre.%m: mese (01-12).%d: giorno del mese (01-31).%H,%M,%S: ore, minuti, secondi.%w: giorno della settimana (0=domenica).%j: giorno dell'anno (001-366).%s: timestamp Unix.%f: secondi con frazioni (SS.SSS).
strftime è anche il modo per estrarre parti di una data: non esiste una funzione EXTRACT o YEAR() separata. Formatti la data fino alla parte che ti interessa e fai il cast se ti serve un numero:
strftime restituisce sempre testo, quindi racchiudilo in CAST(... AS INTEGER) quando vuoi fare calcoli o confronti numerici.
Modificatori: calcoli sulle date senza operatori
È la funzionalità che rende piacevole la gestione delle date in SQLite. Dopo l'argomento temporale puoi passare un numero qualsiasi di stringhe modificatore, che vengono applicate in ordine:
I modificatori che userai di continuo:
'+N days','-N days', e lo stesso perhours,minutes,seconds,months,years.'start of day','start of month','start of year': troncano a quel limite.'weekday N': avanza al prossimo giorno della settimana indicato (0=domenica).'localtime'e'utc': convertono tra fusi orari.
Il trucco dell'"ultimo giorno del mese", inizio del mese, più un mese, meno un giorno, vale la pena di memorizzarlo. SQLite non ha una funzione LAST_DAY, ma concatenare i modificatori ti dà lo stesso risultato.
UTC contro ora locale
'now' restituisce sempre l'ora UTC. Se vuoi l'ora locale, devi chiederla:
Il modificatore 'localtime' converte un valore UTC nel fuso locale del sistema. Il modificatore 'utc' fa il contrario: tratta l'input come ora locale e lo converte in UTC.
L'abitudine sicura: salva tutto in UTC e converti in ora locale solo al momento di mostrarlo. Mescolare fusi orari nei dati salvati porta a bug che si presentano due volte l'anno, al cambio dell'ora legale.
Confrontare date e filtrare intervalli
Se salvi le date come testo ISO 8601, i confronti e BETWEEN funzionano e basta: l'ordine lessicografico di ISO 8601 coincide con quello cronologico. È proprio per questo che è il formato predefinito.
L'intervallo semiaperto (>= start, < end) è un'abitudine utile: evita del tutto la domanda "la mezzanotte del 30 è inclusa o no?".
Per "gli ultimi 7 giorni", lascia che sia SQLite a calcolare il limite:
Differenze tra date
SQLite non ha DATEDIFF. Due schemi coprono tutto:
Le differenze tra julianday() sono in giorni (con precisione frazionaria), quindi moltiplicare per 24 dà le ore, per 1440 i minuti. Le differenze tra strftime('%s', ...) sono in secondi: comode quando vuoi un intero.
CAST(... AS INTEGER) tronca le frazioni di giorno se vuoi contare giorni interi:
Salvare le date: scegli un formato e mantienilo
Tre scelte ragionevoli, in ordine di quanto spesso dovresti sceglierle:
- Testo ISO 8601 (
TEXT). Leggibile nei dump, si ordina correttamente, funziona bene con ogni funzione per le date. La scelta predefinita. - Secondi Unix (
INTEGER). Compatto, confronti veloci, nessuna ambiguità di fuso orario. Ottimo quando hai milioni di righe. Ti serviràdatetime(col, 'unixepoch')per rileggerlo. - Giorno giuliano (
REAL). Raramente conviene, a meno che tu non faccia calcoli pesanti sulle date e voglia una precisione inferiore al secondo in una sola colonna.
Quello che non dovresti fare è mescolare formati nella stessa colonna. Le funzioni per le date accetteranno l'uno e l'altro senza dire nulla, ma indici, ordinamenti e confronti produrranno risultati senza senso.
DEFAULT (datetime('now')) è l'equivalente SQLite di DEFAULT CURRENT_TIMESTAMP: marca ogni nuova riga con l'ora UTC corrente, senza bisogno di codice applicativo.
Raggruppare per periodo di tempo
strftime dà il meglio quando vuoi raggruppare le righe per mese, settimana o ora:
Stessa idea per "ordini per ora del giorno", "iscrizioni per giorno della settimana" o "eventi al minuto": scegli una stringa di formato che catturi solo la granularità che ti interessa, raggruppa su quella e aggrega.
Prossimo passo: le funzioni di aggregazione
A proposito di raggruppamenti: quel COUNT(*) è la più semplice delle funzioni di aggregazione di SQLite. Nella prossima pagina vedremo l'insieme completo: SUM, AVG, MIN, MAX e come riducono molte righe a un unico valore di riepilogo.
Domande frequenti
SQLite ha un tipo di dato DATE o DATETIME?
No: SQLite non ha un tipo dedicato alle date. Le date si salvano come TEXT in formato ISO 8601 ('2026-04-23 10:15:00'), come timestamp Unix INTEGER o come giorno giuliano REAL. Le funzioni integrate per le date accettano tutti e tre i formati e di default restituiscono testo ISO 8601.
Come ottengo la data e l'ora correnti in SQLite?
Usa date('now') per la data corrente, time('now') per l'ora corrente, datetime('now') per entrambe e strftime('%s', 'now') per un timestamp Unix. Di default restituiscono l'ora UTC: passa 'localtime' come modificatore per convertirla: datetime('now', 'localtime').
Come aggiungo giorni o mesi a una data in SQLite?
Passa una stringa modificatore a qualsiasi funzione per le date: date('2026-04-23', '+7 days'), date('now', '-1 month'), datetime('now', '+2 hours', '+30 minutes'). I modificatori si applicano in sequenza, e le unità comprendono days, hours, minutes, seconds, months e years.
Come calcolo la differenza tra due date?
Per i giorni, usa julianday(end) - julianday(start): i giorni giuliani sono numeri in virgola mobile, quindi il risultato include le frazioni di giorno. Per i secondi, sottrai i timestamp Unix: strftime('%s', end) - strftime('%s', start). SQLite non ha una funzione DATEDIFF; questi due schemi coprono quasi tutti i casi.