SQLite tak naprawdę nie ma typu daty
To zaskakuje każdego, kto przychodzi z Postgres lub MySQL. SQLite ma pięć klas przechowywania (NULL, INTEGER, REAL, TEXT, BLOB) i na tym koniec. Nie ma DATE, DATETIME ani TIMESTAMP. Możesz napisać created_at DATETIME w CREATE TABLE i SQLite to przyjmie, ale zapisze wartość jako zwykły tekst lub liczbę.
SQLite daje natomiast zestaw funkcji, które rozumieją trzy przyjęte formaty:
- Tekst ISO 8601:
'2026-04-23','2026-04-23 10:15:00','2026-04-23T10:15:00.123Z'. - Znacznik czasu Unix: sekundy od 1970-01-01 UTC, zapisane jako liczba całkowita.
- Numer dnia juliańskiego: ułamkowe dni od 4714 r. p.n.e., zapisane jako liczba rzeczywista.
Wybierz jeden i się go trzymaj. Tekst ISO 8601 jest najczytelniejszy i poprawnie sortuje się jako ciąg znaków, dlatego jest domyślny.
Cztery sposoby zapytania o "teraz": data tekstowa, data i czas jako tekst, sekundy Unix i dzień juliański. Wszystkie opisują ten sam moment.
Pięć funkcji dat
SQLite ma pięć wbudowanych funkcji, które obejmują prawie wszystko:
date(time, ...): zwracaYYYY-MM-DD.time(time, ...): zwracaHH:MM:SS.datetime(time, ...): zwracaYYYY-MM-DD HH:MM:SS.julianday(time, ...): zwraca liczbę rzeczywistą (świetną do różnic).strftime(format, time, ...): zwraca ciąg w dowolnym formacie.
Każda przyjmuje wartość czasu jako pierwszy argument, a potem dowolną liczbę ciągów modyfikatorów.
Zwróć uwagę na 'unixepoch': w ten sposób mówisz funkcjom dat, że wejściowa liczba całkowita to znacznik czasu Unix, a nie dzień juliański. Bez tego SQLite zakłada, że liczba jest dniem juliańskim.
strftime: własne formaty dat
strftime to koń pociągowy. Kody z % są takie same jak w C czy Pythonie:
Kody, po które sięga się najczęściej:
%Y: rok czterocyfrowy.%m: miesiąc (01-12).%d: dzień miesiąca (01-31).%H,%M,%S: godziny, minuty, sekundy.%w: dzień tygodnia (0 = niedziela).%j: dzień roku (001-366).%s: znacznik czasu Unix.%f: sekundy z częścią ułamkową (SS.SSS).
strftime służy też do wyciągania części daty, bo nie ma osobnej funkcji EXTRACT ani YEAR(). Po prostu formatujesz datę do potrzebnej części i rzutujesz, jeśli potrzebujesz liczby:
strftime zawsze zwraca tekst, więc opakuj go w CAST(... AS INTEGER), gdy chcesz liczyć albo porównywać liczbowo.
Modyfikatory: arytmetyka dat bez operatora
To funkcja, dzięki której praca z datami w SQLite jest przyjemna. Po argumencie czasu możesz przekazać dowolną liczbę ciągów modyfikatorów, które są stosowane po kolei:
Modyfikatory, których będziesz używać bez przerwy:
'+N days','-N days'i to samo dlahours,minutes,seconds,months,years.'start of day','start of month','start of year': przycięcie do tej granicy.'weekday N': przejście do najbliższego podanego dnia tygodnia (0 = niedziela).'localtime'i'utc': przeliczanie między strefami czasowymi.
Sztuczkę z "ostatnim dniem miesiąca" (początek miesiąca, plus jeden miesiąc, minus jeden dzień) warto zapamiętać. SQLite nie ma funkcji LAST_DAY, ale łańcuch modyfikatorów daje to samo.
UTC a czas lokalny
'now' zawsze zwraca UTC. Jeśli chcesz czasu lokalnego, musisz o to poprosić:
Modyfikator 'localtime' przelicza wartość UTC na lokalną strefę systemu. Modyfikator 'utc' robi odwrotnie: traktuje wejście jako czas lokalny i przelicza na UTC.
Bezpieczny nawyk: przechowuj wszystko w UTC, a na czas lokalny przeliczaj tylko przy wyświetlaniu. Mieszanie stref w zapisanych danych prowadzi do błędów, które wychodzą dwa razy w roku przy zmianie czasu.
Porównywanie dat i filtrowanie zakresów
Jeśli zapisujesz daty jako tekst ISO 8601, porównania i BETWEEN po prostu działają: ISO 8601 sortuje się leksykograficznie tak samo jak chronologicznie. To właśnie dlatego jest to format domyślny.
Zakres jednostronnie otwarty (>= start, < end) to przydatny nawyk: całkowicie eliminuje pytanie "czy północ 30. dnia się wliczyła, czy nie?".
Dla "ostatnich 7 dni" pozwól SQLite obliczyć granicę:
Różnice dat
SQLite nie ma DATEDIFF. Wszystko obejmują dwa wzorce:
Różnice julianday() są w dniach (z dokładnością ułamkową), więc mnożenie przez 24 daje godziny, a przez 1440 minuty. Różnice strftime('%s', ...) są w sekundach, co wygodne, gdy chcesz liczby całkowitej.
CAST(... AS INTEGER) obcina ułamki dni, jeśli chcesz liczby pełnych dni:
Przechowywanie dat: wybierz jeden format i się go trzymaj
Trzy rozsądne wybory, w kolejności od najczęściej zalecanego:
- Tekst ISO 8601 (
TEXT). Czytelny w zrzutach, poprawnie się sortuje i dobrze współpracuje z każdą funkcją dat. Wybór domyślny. - Sekundy Unix (
INTEGER). Zwięzłe, szybkie porównania, bez niejednoznaczności stref czasowych. Dobre, gdy masz miliony wierszy. Do odczytu potrzebne jestdatetime(col, 'unixepoch'). - Dzień juliański (
REAL). Rzadko się opłaca, chyba że wykonujesz dużo arytmetyki na datach i chcesz precyzji poniżej sekundy w jednej kolumnie.
Czego nie należy robić, to mieszać formatów w jednej kolumnie. Funkcje dat po cichu przyjmą każdy, ale indeksy, sortowanie i porównania dadzą bzdurne wyniki.
DEFAULT (datetime('now')) to odpowiednik DEFAULT CURRENT_TIMESTAMP w SQLite: oznacza każdy nowy wiersz bieżącym czasem UTC bez udziału kodu aplikacji.
Grupowanie według okresów
strftime błyszczy, gdy chcesz pogrupować wiersze według miesiąca, tygodnia lub godziny:
Ten sam pomysł działa dla "zamówień według godziny dnia", "rejestracji według dnia tygodnia" czy "zdarzeń na minutę": wybierz ciąg formatu, który zachowuje tylko potrzebną ci szczegółowość, pogrupuj według niego i zagreguj.
Dalej: funkcje agregujące
Skoro mowa o grupowaniu: to COUNT(*) to najprostsza z funkcji agregujących SQLite. Następnie przyjrzymy się całemu zestawowi: SUM, AVG, MIN, MAX i temu, jak zamieniają wiele wierszy w jedną wartość podsumowania.
Najczęściej zadawane pytania
Czy SQLite ma typ danych DATE lub DATETIME?
Nie, SQLite nie ma osobnego typu dla dat. Daty zapisuje się jako TEXT w formacie ISO 8601 ('2026-04-23 10:15:00'), jako znacznik czasu Unix typu INTEGER albo jako dzień juliański typu REAL. Wbudowane funkcje dat przyjmują wszystkie trzy formaty i domyślnie zwracają tekst ISO 8601.
Jak pobrać bieżącą datę i czas w SQLite?
Użyj date('now') dla bieżącej daty, time('now') dla bieżącego czasu, datetime('now') dla obu naraz i strftime('%s', 'now') dla znacznika czasu Unix. Domyślnie zwracają one czas UTC. Aby przeliczyć na czas lokalny, przekaż modyfikator 'localtime': datetime('now', 'localtime').
Jak dodać dni lub miesiące do daty w SQLite?
Przekaż ciąg modyfikatora do dowolnej funkcji dat: date('2026-04-23', '+7 days'), date('now', '-1 month'), datetime('now', '+2 hours', '+30 minutes'). Modyfikatory stosuje się po kolei, a dostępne jednostki to days, hours, minutes, seconds, months i years.
Jak obliczyć różnicę między dwiema datami?
Dla dni użyj julianday(end) - julianday(start): dni juliańskie są zmiennoprzecinkowe, więc wynik zawiera ułamki dni. Dla sekund odejmij znaczniki czasu Unix: strftime('%s', end) - strftime('%s', start). SQLite nie ma funkcji DATEDIFF, ale te dwa wzorce obejmują prawie każdy przypadek.