Menu

Date e orari in SQLite: strftime, date(), datetime() e modificatori

Come SQLite salva e manipola le date: le cinque funzioni per le date, le stringhe di formato, i modificatori e le scelte di archiviazione che mantengono veloci le query.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

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, ...): restituisce YYYY-MM-DD.
  • time(time, ...): restituisce HH:MM:SS.
  • datetime(time, ...): restituisce YYYY-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 per hours, 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:

  1. Testo ISO 8601 (TEXT). Leggibile nei dump, si ordina correttamente, funziona bene con ogni funzione per le date. La scelta predefinita.
  2. Secondi Unix (INTEGER). Compatto, confronti veloci, nessuna ambiguità di fuso orario. Ottimo quando hai milioni di righe. Ti servirà datetime(col, 'unixepoch') per rileggerlo.
  3. 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.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA