Menu

Data i czas w SQLite: strftime, date(), datetime() i modyfikatory

Jak SQLite przechowuje daty i na nich operuje: pięć funkcji dat, ciągi formatujące, modyfikatory i wybory dotyczące zapisu, dzięki którym zapytania pozostają szybkie.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

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

  1. Tekst ISO 8601 (TEXT). Czytelny w zrzutach, poprawnie się sortuje i dobrze współpracuje z każdą funkcją dat. Wybór domyślny.
  2. Sekundy Unix (INTEGER). Zwięzłe, szybkie porównania, bez niejednoznaczności stref czasowych. Dobre, gdy masz miliony wierszy. Do odczytu potrzebne jest datetime(col, 'unixepoch').
  3. 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.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ