Jedna data potrafi wywołać sporo zamieszania, gdy baza, aplikacja i użytkownik oczekują innego zapisu. Format YYYY-MM-DD, na przykład 2026-09-16, jest czytelny, jednoznaczny i dobrze sprawdza się w integracjach, ale sposób jego uzyskania zależy od używanego silnika SQL. Pokażę składnię dla SQL Server, MySQL, PostgreSQL, Oracle i SQLite, a także wyjaśnię, kiedy formatować datę, a kiedy pozostawić ją jako typ daty.
YYYY-MM-DD jest proste w użyciu, jeśli rozdzielisz datę od jej prezentacji
- YYYY-MM-DD oznacza kolejno rok, miesiąc i dzień.
-
SQL Server używa stylu 23 w funkcji
CONVERT. -
MySQL formatuje daty przez DATE_FORMAT z maską
%Y-%m-%d. -
PostgreSQL i Oracle korzystają z funkcji TO_CHAR i maski
YYYY-MM-DD. - Do filtrowania danych lepiej używać typów daty i parametrów, a nie porównywać sformatowany tekst.
Co oznacza zapis YYYY-MM-DD i dlaczego działa dobrze
Zapis YYYY-MM-DD składa się z czterocyfrowego roku, dwucyfrowego miesiąca i dwucyfrowego dnia. Data 2026-09-16 nie pozostawia miejsca na interpretację, czy chodzi o 16 września, czy o 9 czerwca, co zdarza się przy formatach takich jak 09/06/2026.
Ten układ jest zgodny z popularną reprezentacją ISO 8601 i dobrze sortuje się jako tekst. Warto jednak rozdzielić dwie rzeczy: data w bazie powinna mieć typ DATE lub DATETIME, natomiast zapis YYYY-MM-DD jest najczęściej sposobem jej wyświetlenia albo przekazania do innego systemu.
Jeżeli kolumna ma typ daty, baza może poprawnie porównywać wartości, dodawać dni i sprawdzać zakresy. Gdy przechowasz datę jako VARCHAR, zyskasz pozorną elastyczność, ale szybko pojawią się problemy z walidacją, sortowaniem i godzinami zapisanymi w różnych strefach.
Znaczenie znaków w masce
| Element | Znaczenie | Przykład |
|---|---|---|
YYYY lub %Y
|
Rok zapisany czterema cyframi | 2026 |
MM lub %m
|
Miesiąc z zerem wiodącym | 09 |
DD lub %d
|
Dzień miesiąca z zerem wiodącym | 16 |
Maska nie jest jednak uniwersalna dla każdego silnika. SQL Server używa numerowanych stylów, MySQL stosuje znaczniki z procentem, a PostgreSQL i Oracle korzystają z modeli formatowania. To jedna z najczęstszych przyczyn błędów przy przenoszeniu zapytań między bazami.
Jak uzyskać format YYYY-MM-DD w popularnych silnikach
| Silnik | Przykład formatowania | Wynik |
|---|---|---|
| SQL Server | CONVERT(char(10), order_date, 23) |
2026-09-16 |
| MySQL | DATE_FORMAT(order_date, '%Y-%m-%d') |
2026-09-16 |
| PostgreSQL | TO_CHAR(order_date, 'YYYY-MM-DD') |
2026-09-16 |
| Oracle | TO_CHAR(order_date, 'YYYY-MM-DD') |
2026-09-16 |
| SQLite | strftime('%Y-%m-%d', order_date) |
2026-09-16 |
SQL Server
W SQL Server najprościej użyć stylu 23, który zwraca datę jako yyyy-mm-dd. Przykład dla tabeli zamówień wygląda tak:
SELECT
CONVERT(char(10), order_date, 23) AS order_date
FROM orders;Jeżeli nie potrzebujesz tekstu, tylko samej daty bez godziny, lepsze będzie rzutowanie na typ date:
SELECT CAST(order_date AS date) AS order_date
FROM orders;W aplikacjach .NET można spotkać format yyyy-MM-dd używany przez biblioteki formatowania. Nie należy jednak bezrefleksyjnie przenosić tej składni do SQL Server. Dla stałego formatu w zapytaniu preferuję CONVERT ze stylem 23, ponieważ jasno pokazuje intencję i nie wymaga kosztownego formatowania lokalizacyjnego.
MySQL
W MySQL używa się funkcji DATE_FORMAT. Wielkie %Y oznacza rok czterocyfrowy, %m miesiąc, a %d dzień:
SELECT
DATE_FORMAT(order_date, '%Y-%m-%d') AS order_date
FROM orders;Jeśli kolumna zawiera godzinę, a potrzebujesz wartości typu data, możesz użyć DATE(order_date). To nie jest dokładnie to samo co formatowanie do tekstu. DATE zwraca datę, a DATE_FORMAT zwraca sformatowany ciąg znaków, więc wybór zależy od tego, co ma zrobić dalsza część zapytania.
PostgreSQL i Oracle
W PostgreSQL oraz Oracle popularnym rozwiązaniem jest TO_CHAR:
SELECT
TO_CHAR(order_date, 'YYYY-MM-DD') AS order_date
FROM orders;W obu silnikach wielkość liter w masce może mieć znaczenie dla części elementów formatowania, dlatego zapisuję model konsekwentnie jako YYYY-MM-DD. W PostgreSQL warto też pamiętać, że YYYY oznacza rok kalendarzowy, natomiast IYYY odnosi się do roku ISO używanego przy numerowaniu tygodni. Do zwykłych dat używaj YYYY.
SQLite
SQLite korzysta z funkcji strftime:
SELECT
strftime('%Y-%m-%d', order_date) AS order_date
FROM orders;W przypadku danych zapisanych już w standardowej postaci SQLite często wystarczy również funkcja date(order_date). Trzeba tylko pamiętać, że SQLite nie ma tak rozbudowanego systemu typów dat jak SQL Server czy PostgreSQL, dlatego walidacja danych wejściowych spoczywa w większej mierze na aplikacji.
Wyświetlenie daty to nie to samo co konwersja i filtrowanie
Formatowanie wyniku zapytania
Formatowanie ma sens wtedy, gdy przygotowujesz dane do raportu, eksportu CSV, odpowiedzi API albo widoku administracyjnego. Funkcja zwracająca tekst jest wtedy właściwym narzędziem, bo odbiorca potrzebuje konkretnego zapisu, a nie obiektu daty.
SELECT
CONVERT(char(10), created_at, 23) AS created_date
FROM users;Takie wyrażenie może jednak utrudnić dalsze operacje. Po użyciu CONVERT, TO_CHAR albo DATE_FORMAT wynik jest tekstem, więc nie powinien być traktowany jak pełnoprawna wartość daty.
Konwersja do typu DATE
Jeśli celem jest usunięcie godziny, konwertuj wartość do typu daty zamiast tworzyć tekst. W SQL Server będzie to CAST(created_at AS date), w PostgreSQL created_at::date, a w MySQL DATE(created_at).
To rozróżnienie robi dużą różnicę w kodzie aplikacji. Typ DATE zachowuje znaczenie biznesowe wartości, natomiast tekst w formacie YYYY-MM-DD jest tylko jej prezentacją.
Przeczytaj również: Pętla do-while w C# - składnia, przykłady i pułapki
Filtrowanie całego dnia
Typowy błąd pojawia się przy wyszukiwaniu rekordów z konkretnego dnia. Dla kolumny typu datetime warunek równości może pominąć wpisy zawierające godzinę. Bezpieczniejszy jest przedział otwarty z prawej strony:
WHERE created_at >= '2026-09-16'
AND created_at < '2026-09-17'Takie podejście obejmuje cały dzień, niezależnie od tego, czy rekord powstał o północy, czy o 23:59:59. Dodatkowo zwykle lepiej współpracuje z indeksem niż formatowanie kolumny w klauzuli WHERE.
Typowe błędy przy pracy z datami w SQL
- Przechowywanie daty jako VARCHAR zamiast w kolumnie typu DATE, DATETIME lub TIMESTAMP. To utrudnia sortowanie i walidację.
-
Używanie nie tej maski. W MySQL poprawne będzie
%Y-%m-%d, a w PostgreSQLYYYY-MM-DD. -
Pomylenie miesiąca z minutą. W niektórych bibliotekach
MMoznacza miesiąc, ammminuty. Nie przenoś masek między SQL i .NET bez sprawdzenia dokumentacji. -
Konwersja kolumny w WHERE, na przykład przez
TO_CHARlubFORMAT. Czytelność rośnie, ale zapytanie może stracić możliwość efektywnego użycia indeksu. -
Niejawna konwersja zależna od ustawień sesji. Daty zapisane jako
16/09/2026mogą być różnie interpretowane w zależności od języka i ustawień serwera. - Ignorowanie strefy czasowej. Zamiana znacznika czasu na samą datę przed przeliczeniem strefy może przesunąć wynik na poprzedni albo następny dzień.
Najbezpieczniej przekazywać daty do zapytań jako parametry typowane, a nie sklejać SQL z tekstu pochodzącego od użytkownika. Zyskujesz wtedy poprawną konwersję, ochronę przed SQL injection i mniejsze ryzyko błędów lokalizacyjnych.
Dla codziennej pracy wybierz typ daty, a format zostaw na końcu
Jeżeli chcesz tylko pokazać datę jako 2026-09-16, użyj funkcji właściwej dla konkretnego silnika. SQL Server potrzebuje stylu 23, MySQL maski %Y-%m-%d, a PostgreSQL i Oracle modelu YYYY-MM-DD.
Moja praktyczna reguła jest prosta: przechowuj i filtruj daty jako daty, formatuj je dopiero przy prezentacji. Dzięki temu baza zachowuje możliwość prawidłowego sortowania, indeksowania i wykonywania operacji na czasie, a aplikacja może bez problemu dopasować wygląd wartości do potrzeb użytkownika.
