Strefa czasowa nie jest tylko liczbą godzin dodawaną do UTC. To zbiór historycznych i przyszłych reguł dla regionu. Rządy zmieniają offsety i zasady czasu letniego, czasem z niewielkim wyprzedzeniem. Lokalna godzina może przez to nie istnieć albo wystąpić dwukrotnie. Kalendarz, booking i scheduler muszą potraktować tę niejednoznaczność jako element modelu danych.
Offset jest zdjęciem jednej chwili
+02:00 opisuje relację lokalnego zegara do UTC w konkretnym momencie. Nie mówi, jaki offset będzie zimą, za rok lub trzydzieści lat temu. Nazwa IANA, na przykład Europe/Warsaw, wskazuje bazę reguł.
Dla istniejącego instantu offset wystarcza do jednoznaczności. Dla „w każdy poniedziałek o 9:00” trzeba zachować region.
Wiosną część lokalnych godzin nie istnieje
Przy przejściu na czas letni zegar może przeskoczyć z 01:59 na 03:00. Spotkanie o 02:30 nie ma wtedy odpowiadającego instantu. Biblioteki przesuwają, odrzucają albo normalizują taką wartość według własnych reguł.
Produkt powinien zdecydować świadomie. Budzik może wybrać następną poprawną chwilę, transakcja prawna może wymagać błędu, a kalendarz powinien ostrzec użytkownika.
Jesienią ta sama godzina występuje dwa razy
Po cofnięciu zegara lokalne 02:30 może oznaczać dwa instants z różnymi offsetami. Sama data, godzina i nazwa regionu wymagają dodatkowej reguły wyboru.
Formularz może zapisać wybrany offset albo określić earlier/later occurrence. Logi powinny zawierać instant lub offset, aby zdarzenia zachowały kolejność.
Skróty stref są wieloznaczne
CST może oznaczać kilka regionów. Skrót nadaje się do prezentacji, ale nie jako trwały identyfikator. Nazwy IANA są dłuższe i bardziej precyzyjne.
Stały „GMT+2” również nie zastępuje regionu, jeśli znaczenie obejmuje zmianę czasu i historię. Model ma zachować intencję, nie tylko dzisiejszy wynik.
Baza stref czasowych podlega aktualizacjom
System operacyjny i runtime zawierają wersję tzdata. Po politycznej zmianie serwer, kontener i telefon mogą wyliczać przyszły termin inaczej, dopóki wszystkie nie zostaną zaktualizowane.
Długoterminowe planowanie potrzebuje reguły, czy przyszłe instants są przeliczane po aktualizacji. Lot i ustawowy deadline mogą mieć różne wymagania.
Wersja tzdata jest częścią odtwarzalności
Jeżeli system musi wyjaśnić, dlaczego rok temu wyliczył konkretny offset dla przyszłej daty, sama nazwa strefy może nie wystarczyć. Audit może zapisać wersję danych czasowych używaną przy materializacji harmonogramu.
Nie zawsze trzeba przechowywać pełną bazę. Warto jednak wiedzieć, kiedy aktualizacja weszła na serwery i które terminy zostały ponownie przeliczone. Rollout tzdata powinien mieć testy podobnie jak upgrade biblioteki.
Dzień kalendarzowy nie zawsze ma 24 godziny
„Jutro o tej samej lokalnej godzinie” i „za 24 godziny” różnią się przy DST. Pierwsze jest operacją kalendarzową, drugie duration na osi czasu.
Timeout używa duration i monotonic clock. Codzienny raport używa lokalnej reguły. Jedno dodawanie sekund nie obsłuży obu przypadków.
Miesiąc nie ma stałej długości
Miesiące mają od 28 do 31 dni. Co ma znaczyć płatność miesięczna ustawiona na 31.? Ostatni dzień, pominięcie czy błąd? Domyślna decyzja biblioteki nie musi odpowiadać biznesowi.
Reguła cykliczna powinna zachowywać politykę. Sam wyliczony następny timestamp traci informację, dlaczego wybrano tę datę.
Billing i deadline potrzebują zasad kalendarza biznesowego
„Następny dzień roboczy” zależy od kraju, świąt i czasem konkretnej instytucji. Weekend nie jest jedyną regułą. Biblioteka dat nie zna automatycznie kalendarza bankowego lub firmowego.
Kalendarz powinien być wersjonowany i mieć właściciela. Zmiana listy świąt może wpływać na istniejące harmonogramy, dlatego trzeba określić, czy przelicza się przyszłe terminy i jak informuje użytkownika.
Parser lokalnego czasu nie powinien zgadywać
String 01/02/2026 10:00 może oznaczać różne daty zależnie od locale. API powinno przyjmować jednoznaczny format maszynowy, a UI parsować według jawnie wybranego języka i strefy.
Gdy lokalna godzina jest ambiguous, biblioteka powinna zwrócić stan wymagający decyzji zamiast cicho wybierać pierwszy offset. Taka jawność pozwala produktowi zastosować własną politykę.
Local date i instant to inne typy
Urodziny, dzień dostawy lub święto często nie mają godziny ani strefy. Zamiana takiej daty na północ w przypadkowym regionie i późniejsza konwersja może pokazać poprzedni dzień.
Video call i płatność są konkretnymi chwilami. Schema i nazwy typów powinny odróżniać te pojęcia.
Strefa użytkownika nie zawsze jest strefą wydarzenia
Podróżny może oglądać rezerwację w swoim bieżącym regionie, ale check-in o 15:00 należy do strefy hotelu. Automatyczne wykrycie browsera jest dobrą podpowiedzią, lecz nie dowodem intencji.
Interfejs powinien jasno wyświetlać nazwę strefy i pozwalać wybrać właściwy kontekst.
Domyślna strefa serwera tworzy ukrytą zależność
Kod używający lokalnych funkcji może działać na laptopie i zmienić wynik w kontenerze UTC. Połączenie z bazą może mieć jeszcze inną session timezone.
Produkcja powinna mieć świadome defaults, a logika domenowa przekazywać strefę jawnie. Test uruchomiony w kilku konfiguracjach wykrywa założenia.
Testy muszą trafić w granice kalendarza
Zwykły lutowy dzień nie ujawni problemu DST. Fixtures powinny obejmować moment przed, w trakcie i po zmianie, leap year, koniec miesiąca oraz region bez czasu letniego.
Warto sprawdzać wynikowy instant, offset i zachowaną nazwę strefy, nie tylko sformatowany string.
Formatowanie należy do prezentacji
W środku systemu czas pozostaje strukturą. Dopiero UI wybiera locale, strefę, format 12/24 i nazwy miesięcy. Gotowy tekst trudno sortować i ponownie przeliczać.
Strefy stają się zarządzalne, gdy model rozdziela instant, local date, local time, duration i recurrence. Każda konwersja powinna mieć jawny region i politykę niejednoznaczności.