SQLite hat eigentlich keinen echten Datentyp für Datum
Das bringt jeden ins Straucheln, der von Postgres oder MySQL kommt. SQLite kennt nur fünf Storage Classes — NULL, INTEGER, REAL, TEXT, BLOB — und damit hat sich's. Es gibt kein DATE, kein DATETIME, keinen TIMESTAMP. Du kannst zwar created_at DATETIME in dein CREATE TABLE schreiben, und SQLite schluckt das auch klaglos, aber intern landet der Wert schlicht als Text oder Zahl.
Was SQLite dir stattdessen mitgibt, ist eine Reihe von Funktionen, die drei gängige Formate verstehen:
- ISO-8601-Text —
'2026-04-23','2026-04-23 10:15:00','2026-04-23T10:15:00.123Z'. - Unix-Timestamp — Sekunden seit dem 1.1.1970 UTC, gespeichert als Integer.
- Julianisches Datum — Bruchteil von Tagen seit 4714 v. Chr., gespeichert als Real.
Entscheide dich für eines und bleib konsequent dabei. ISO-8601-Text ist am besten lesbar und sortiert als String korrekt — deshalb ist es auch die übliche Wahl.
Vier Wege, die aktuelle Zeit abzufragen – als Text-Datum, Text-Zeitstempel, Unix-Sekunden oder Julianisches Datum. Alle vier beschreiben denselben Moment.
Die fünf Datumsfunktionen in SQLite
SQLite bringt fünf eingebaute Funktionen mit, die so gut wie alles abdecken, was du mit Datum und Uhrzeit machen willst:
date(time, ...)– liefertYYYY-MM-DD.time(time, ...)– liefertHH:MM:SS.datetime(time, ...)– liefertYYYY-MM-DD HH:MM:SS.julianday(time, ...)– liefert einen Fließkommawert (ideal, um Datumsdifferenzen zu berechnen).strftime(format, time, ...)– liefert einen frei formatierten String.
Jede dieser Funktionen erwartet als erstes Argument einen Zeitwert, gefolgt von beliebig vielen Modifier-Strings.
Beachte den Modifier 'unixepoch' — damit signalisierst du den Datumsfunktionen, dass die Eingabe ein Unix-Timestamp ist und kein julianisches Datum. Lässt du ihn weg, geht SQLite automatisch von einem Julian Day aus.
strftime: eigenes SQLite Date Format definieren
strftime ist das Schweizer Taschenmesser unter den Datumsfunktionen in SQLite. Die %-Platzhalter kennst du wahrscheinlich schon aus C oder Python:
Die Format-Codes, die du am häufigsten brauchst:
%Y— vierstelliges Jahr.%m— Monat (01-12).%d— Tag im Monat (01-31).%H,%M,%S— Stunden, Minuten, Sekunden.%w— Wochentag (0=Sonntag).%j— Tag im Jahr (001-366).%s— Unix-Timestamp.%f— Sekundenbruchteile (SS.SSS).
Mit strftime extrahierst du gleichzeitig auch einzelne Bestandteile eines Datums — eine separate EXTRACT- oder YEAR()-Funktion gibt es in SQLite nicht. Du formatierst das Datum einfach so weit herunter, bis nur noch der gewünschte Teil übrig bleibt, und castest ihn bei Bedarf in eine Zahl:
strftime liefert immer Text zurück. Wenn du also rechnen oder numerisch vergleichen willst, packst du das Ergebnis in CAST(... AS INTEGER).
Modifier: Datumsarithmetik ohne Rechenzeichen
Genau dieses Feature macht den Umgang mit Datumsangaben in SQLite so angenehm. Nach dem Zeitargument kannst du beliebig viele Modifier-Strings übergeben, die dann der Reihe nach abgearbeitet werden:
Modifier, die du ständig brauchst:
'+N days','-N days'und das Gleiche fürhours,minutes,seconds,months,years.'start of day','start of month','start of year'— schneidet auf die jeweilige Grenze ab.'weekday N'— springt zum nächsten angegebenen Wochentag (0 = Sonntag).'localtime'und'utc'— wechselt zwischen den Zeitzonen.
Den Trick mit dem „letzten Tag des Monats" solltest du dir merken: start of month, dann einen Monat dazu und einen Tag wieder abziehen. SQLite hat zwar keine LAST_DAY-Funktion, aber durch das Verketten von Modifiern kommst du aufs gleiche Ergebnis.
UTC vs. lokale Zeit
'now' liefert immer UTC zurück. Wenn du die lokale Zeit willst, musst du explizit danach fragen:
Der Modifier 'localtime' rechnet einen UTC-Wert in die lokale Systemzeitzone um. 'utc' macht das Gegenteil – er interpretiert den Eingabewert als Lokalzeit und wandelt ihn in UTC um.
Eine bewährte Regel: Speichere alles in UTC und konvertiere nur bei der Anzeige in die Lokalzeit. Wer in der Datenbank verschiedene Zeitzonen vermischt, handelt sich Bugs ein, die zuverlässig zweimal im Jahr auftauchen – nämlich bei der Sommerzeitumstellung.
Datumsvergleiche und Bereichsfilter mit BETWEEN
Wenn du Datumswerte als ISO-8601-Text ablegst, funktionieren Vergleiche und BETWEEN ohne weiteres Zutun – ISO 8601 sortiert lexikografisch nämlich exakt so wie chronologisch. Genau deshalb ist dieses Format auch der Standard.
Das halboffene Intervall (>= start, < end) ist eine gute Angewohnheit – damit umgeht man die typische Frage „Zählt Mitternacht am 30. jetzt mit oder nicht?" komplett.
Für „die letzten 7 Tage" lässt du SQLite die Grenze selbst ausrechnen:
Datumsdifferenz berechnen
In SQLite gibt es kein DATEDIFF – aber keine Sorge: Mit zwei Mustern deckst du eigentlich alle Fälle ab:
Differenzen über julianday() werden in Tagen ausgedrückt (inklusive Nachkommastellen). Multiplizierst du das Ergebnis mit 24, bekommst du Stunden, mit 1440 entsprechend Minuten. Differenzen mit strftime('%s', ...) liefern dagegen Sekunden – praktisch, wenn du direkt einen ganzzahligen Wert brauchst.
Mit CAST(... AS INTEGER) schneidest du die Nachkommastellen ab, falls du ganze Tage zählen willst:
Datum in SQLite speichern: ein Format wählen und dabei bleiben
Drei vernünftige Optionen, sortiert nach der Häufigkeit, mit der du sie nehmen solltest:
- ISO-8601-Text (
TEXT). Lesbar in Dumps, sortiert korrekt und harmoniert mit allen Datumsfunktionen. Die Standardwahl. - Unix-Sekunden (
INTEGER). Kompakt, schnelle Vergleiche, keine Zeitzonen-Stolperfallen. Sinnvoll bei Millionen von Zeilen. Zum Auslesen brauchst du danndatetime(col, 'unixepoch'). - Julianischer Tag (
REAL). Lohnt sich selten – höchstens, wenn du intensiv mit Datumsarithmetik arbeitest und in einer einzigen Spalte Genauigkeit unterhalb der Sekunde brauchst.
Was du auf gar keinen Fall machen solltest: verschiedene Formate in derselben Spalte mischen. Die Datumsfunktionen schlucken zwar beides klaglos, aber Indizes, Sortierungen und Vergleiche liefern dann puren Unsinn.
DEFAULT (datetime('now')) ist das SQLite-Pendant zu DEFAULT CURRENT_TIMESTAMP – jeder neue Datensatz bekommt damit automatisch die aktuelle UTC-Zeit verpasst, ganz ohne Zutun aus dem Anwendungscode.
Nach Zeitraum gruppieren
strftime spielt seine Stärken aus, wenn du Datensätze nach Monat, Woche oder Stunde bündeln willst:
Dasselbe Prinzip funktioniert auch für „Bestellungen pro Tagesstunde", „Anmeldungen pro Wochentag" oder „Events pro Minute" – du wählst einfach einen Format-String, der genau die gewünschte Granularität abbildet, gruppierst danach und aggregierst.
Als Nächstes: Aggregatfunktionen
Apropos Gruppieren – COUNT(*) ist die simpelste der Aggregatfunktionen in SQLite. Im nächsten Abschnitt schauen wir uns das ganze Arsenal an: SUM, AVG, MIN, MAX und wie sie viele Zeilen zu einem einzigen Ergebniswert zusammenfassen.
Häufig gestellte Fragen
Hat SQLite überhaupt einen DATE- oder DATETIME-Datentyp?
Nein — einen eigenen Datumstyp gibt es in SQLite nicht. Du speicherst Datumswerte entweder als TEXT im ISO-8601-Format ('2026-04-23 10:15:00'), als Unix-Timestamp INTEGER oder als Julianisches Datum REAL. Die eingebauten Datumsfunktionen kommen mit allen drei Varianten klar und liefern standardmäßig ISO-8601-Text zurück.
Wie bekomme ich das aktuelle Datum bzw. die aktuelle Uhrzeit in SQLite?
date('now') liefert das heutige Datum, time('now') die Uhrzeit, datetime('now') beides zusammen und strftime('%s', 'now') einen Unix-Timestamp. Die Werte sind standardmäßig in UTC — mit dem Modifier 'localtime' rechnest du in die lokale Zeitzone um, z. B. datetime('now', 'localtime').
Wie addiere ich Tage oder Monate auf ein Datum?
Du hängst einfach einen oder mehrere Modifier-Strings an die Datumsfunktion an: date('2026-04-23', '+7 days'), date('now', '-1 month') oder datetime('now', '+2 hours', '+30 minutes'). Die Modifier werden der Reihe nach angewendet, gültige Einheiten sind unter anderem days, hours, minutes, seconds, months und years.
Wie berechne ich die Differenz zwischen zwei Datumswerten?
Für Tage nimmst du julianday(end) - julianday(start) — Julianische Tage sind Fließkommazahlen, Bruchteile von Tagen sind also drin. Für Sekunden ziehst du Unix-Timestamps voneinander ab: strftime('%s', end) - strftime('%s', start). Eine DATEDIFF-Funktion gibt es in SQLite nicht, aber diese beiden Muster decken praktisch alle Fälle ab.