Praca z datami w programowaniu to temat, który potrafi sprawić wiele problemów. Strefy czasowe, lata przestępne, różne formaty dat czy nawet przestępna sekunda mogą sprawić, że to, co wydaje się proste, staje się pułapką dla programistów i użytkowników.
Dlaczego daty są trudniejsze, niż wyglądają
Praca z datami w programowaniu to temat, który potrafi zaskoczyć nawet doświadczonych programistów. Strefy czasowe, lata przestępne, różne formaty zapisu czy przestępna sekunda — każdy z tych elementów z osobna wydaje się prosty, ale w połączeniu z wymaganiami biznesowymi tworzą pole minowe. W trakcie audytów aplikacji webowych regularnie trafiamy na błędy związane z datami: zamówienia przypisane do złego dnia, raporty z przesuniętymi godzinami, powiadomienia wysyłane o północy zamiast rano. Ten artykuł zbiera pułapki, na które natknęliśmy się w praktyce, i podpowiada, jak ich unikać.
Format daty — różne standardy w różnych krajach
DD/MM/YYYY czy MM/DD/YYYY? W Europie standardem jest dzień/miesiąc/rok, ale w USA powszechnie stosuje się miesiąc/dzień/rok. Zapis 03/04/2025 to 3 kwietnia w Polsce i 4 marca w Stanach. Przy wymianie danych między systemami takie dwuznaczności prowadzą do błędów, które trudno wychwycić automatycznie.
W warstwie backendu i API stosuj format ISO 8601 (YYYY-MM-DD) — jest jednoznaczny niezależnie od lokalizacji. W interfejsie wyświetlaj datę w formacie zrozumiałym dla użytkownika, najlepiej korzystając z Intl.DateTimeFormat w JavaScript lub funkcji strftime z ustawieniami lokalizacji po stronie serwera. Standard ISO 8601 definiuje też zapis czasu ze strefą (2025-07-15T14:30:00+02:00), co eliminuje wątpliwości przy przesyłaniu timestampów.
Strefy czasowe — jeden moment, różne godziny
Serwer przechowuje czas w UTC, użytkownik w Krakowie widzi CET/CEST, a klient w Nowym Jorku — EST/EDT. Sam mechanizm konwersji nie jest skomplikowany, ale problemy pojawiają się przy zmianie czasu (DST). W Polsce zegarki przesuwamy dwa razy w roku — w marcu godzina 2:30 nie istnieje, a w październiku godzina 2:30 występuje dwa razy. Aplikacja, która pozwala zaplanować spotkanie na „2:30 w nocy w ostatnią niedzielę października", musi wiedzieć, o którą 2:30 chodzi.
Przechowuj czas w UTC i konwertuj go do lokalnej strefy użytkownika dopiero przy wyświetlaniu. Do konwersji w JavaScript używaj date-fns lub day.js z pluginem timezone — obie biblioteki są lekkie i aktywnie rozwijane. Popularna kiedyś biblioteka Moment.js jest uznawana za przestarzałą (oficjalnie w trybie maintenance od 2020 roku), ale day.js zachowuje kompatybilną składnię, więc migracja jest stosunkowo prosta.
Ciekawostka: Kiribati w 1995 roku przesunęło swoje wyspy z UTC-11 na UTC+13, żeby cały kraj był w tym samym dniu kalendarzowym. To nie żart — baza stref czasowych IANA (tzdata) notuje takie przypadki, dlatego warto ją aktualizować przy każdym wdrożeniu.
Lata przestępne i przestępna sekunda
Rok przestępny to nie tylko „co cztery lata dodajemy 29 lutego". Lata podzielne przez 100 nie są przestępne, chyba że są podzielne przez 400 — rok 2000 był przestępny, ale 1900 nie. Błąd w tej logice w arkuszu kalkulacyjnym Lotus 1-2-3 (1983) został skopiowany do Excela dla zachowania kompatybilności i tkwi tam do dziś.
Przestępna sekunda to zjawisko rzadsze — ostatnią dodano 31 grudnia 2016 roku. W 2022 roku organizacja CGPM (Conférence Générale des Poids et Mesures) podjęła decyzję o wycofaniu sekund przestępnych do 2035 roku. W praktyce większość systemów synchronizuje się z serwerami NTP, które rozkładają dodatkową sekundę na dłuższy okres (tzw. leap smearing), więc aplikacja webowa raczej tego nie odczuje. Jeśli jednak budujesz system pomiarowy z dokładnością do milisekund — miej to na uwadze.
UI wyboru daty — jak nie frustrować użytkownika
Komponent date-picker powinien pozwalać zarówno na wybór z kalendarza, jak i na ręczne wpisanie daty. Uporczywe klikanie strzałek, żeby dotrzeć do roku urodzenia, to częsty powód frustracji — widziałem to wielokrotnie w testach użyteczności. Przy zakresach dat blokuj możliwość wybrania daty końcowej wcześniejszej niż początkowa. Predefiniowane zakresy („ostatnie 7 dni", „bieżący miesiąc", „kwartał") przyspieszają codzienną pracę z raportami.
W interfejsie stosuj formaty „human-readable" tam, gdzie ma to sens: „2 dni temu", „za 3 godziny", „w poniedziałek". Użytkownicy przyswajają takie informacje szybciej niż surową datę z godziną. Biblioteki date-fns (formatDistance) i day.js (fromNow) oferują gotowe funkcje do tego.
Kiedy zaczyna się nowy dzień — to zależy od branży
Dzień zwykle zaczyna się o 00:00, ale w systemach hotelowych doba zaczyna się o 14:00 (check-in), a w lotnictwie bywa inaczej w zależności od linii. W Japonii w rozkładach jazdy stosuje się godziny przekraczające 24:00 — np. „28:00" oznacza 4:00 następnego dnia. Podobna konwencja funkcjonuje w polskiej telewizji przy nocnych ramówkach. Pierwszy dzień tygodnia też nie jest uniwersalny: w USA i Kanadzie tydzień zaczyna się w niedzielę, w Europie — w poniedziałek (standard ISO 8601).
Dostosuj logikę aplikacji do kontekstu branżowego. Przy budowie systemów dedykowanych analizujemy te niuanse na etapie zbierania wymagań, bo poprawki w gotowym systemie kosztują wielokrotnie więcej.
Timestampy kontra daty tekstowe
Timestamp Unix (np. 1700000000) to liczba sekund od 1 stycznia 1970 UTC. Jest jednoznaczny, łatwy do porównywania i sortowania. Daty tekstowe ("2025-07-15") są czytelniejsze dla człowieka, ale wymagają parsowania i informacji o strefie czasowej. Do przechowywania i obliczeń używaj timestampów lub typów DATETIME/TIMESTAMPTZ w bazie danych. W interfejsie wyświetlaj datę w formacie lokalnym. W PHP polegaj na klasie DateTime i bibliotece Carbon, w JavaScript — na Date lub date-fns.
Co z tym zrobić u siebie
- Sprawdź, czy Twój backend przechowuje czas w UTC — jeśli nie, zaplanuj migrację, zanim system się rozrośnie.
- Przetestuj aplikację w dniu zmiany czasu (DST) — wiele błędów ujawnia się dopiero wtedy.
- Zastąp Moment.js lżejszą biblioteką (day.js lub date-fns), jeśli jeszcze tego nie zrobiłeś.
- Jeśli budujesz system z kalendarzami, rezerwacjami lub raportami czasowymi — projektujemy takie rozwiązania z uwzględnieniem pułapek opisanych wyżej.
Źródła
- W3C — Date and Time Formats — specyfikacja formatów daty i czasu zgodnych z ISO 8601.
- Wikipedia — Czas letni — historia i zasady zmiany czasu w Polsce i na świecie.
- IANA Time Zone Database — oficjalna baza stref czasowych używana przez systemy operacyjne i biblioteki.
- TC39 Temporal Proposal — nowe API dat w JavaScript (etap zaawansowany, zastąpi niedoskonały obiekt Date).