Znaczniki czasu, strefy czasowe i godzina, która zdarza się dwa razy

Co naprawdę zlicza czas uniksowy, czym przesunięcia w ISO 8601 różnią się od stref czasowych IANA, co czas letni robi z alarmami i czasami trwania oraz kiedy przechowywanie UTC jest złą odpowiedzią.

Znacznik czasu odpowiada na jedno z dwóch pytań, a większość błędów z datami bierze się z mylenia ich ze sobą. Nazywa albo chwilę, czyli punkt na osi czasu, co do którego zgadzają się wszyscy obserwatorzy, albo wskazanie zegara na ścianie, które nic nie znaczy, dopóki nie wiadomo, czyja to ściana. Płatność wydarzyła się w konkretnej chwili; wizyta u dentysty jest wskazaniem zegara. Zapisz jedno jako drugie, a rozsypie się później, dokładnie o godzinę, w niedzielny poranek.

Czas uniksowy zlicza, a nie podaje godziny

Czas uniksowy to liczba sekund, które upłynęły od 1970-01-01 00:00:00 UTC. To UTC mówi, gdzie zaczęło się zliczanie; sama wartość nie niesie żadnej strefy czasowej. Ta sama chwila to ta sama liczba w Amsterdamie, Auckland i Limie.

Problemem jest jednostka, więc policz cyfry.

CyfryPrzykładJednostka
101756080000sekundy
131756080000000milisekundy

Każda dzisiejsza data ma 10 cyfr w sekundach i 13 w milisekundach, i tak będzie aż do roku 2286. Oba błędne odczyty są głośne: milisekundy odczytane jako sekundy lądują w roku 57626, a sekundy odczytane jako milisekundy w styczniu 1970. Konwerter znaczników czasu pokazujący zinterpretowaną datę czyni to oczywistym.

Drugim ograniczeniem jest pojemnik. Zliczanie sekund w 32 bitach ze znakiem kończy się na 2147483647, czyli o 03:14:07 UTC 19 stycznia 2038 roku, po czym zawija się na wartość ujemną i odczytuje jako grudzień 1901. Wszystko, co przechowuje trzydziestoletni termin ważności, już dziś liczy poza tę granicę. Trzydzieści dwa bity bez znaku sięgają roku 2106, ale tracą każdą datę sprzed 1970; 64 bity nie mają praktycznego sufitu.

ISO 8601 i RFC 3339

Postacią wartą zapamiętania jest 2026-08-25T14:30:00Z: data, litera T, godzina, a potem oznaczenie strefy. RFC 3339 jest ściślejszym profilem ISO 8601 przeznaczonym dla protokołów internetowych i wymaga tego oznaczenia. Samo ISO 8601 dopuszcza też daty tygodniowe, postać bez separatorów, taką jak 20260825T143000Z, oraz znaczniki czasu bez przesunięcia, więc API obiecujące "ISO 8601" zwykle ma na myśli podzbiór z RFC 3339.

Z oznacza przesunięcie zerowe. +02:00 oznacza, że zegar lokalny wyprzedza UTC o dwie godziny, więc UTC uzyskuje się przez odejmowanie; odwrócenie tego jest częstym błędem o dwie godziny.

Ciąg znakówCo nazywa
2026-08-25T14:30:00ZChwilę, jednoznacznie
2026-08-25T16:30:00+02:00Tę samą chwilę, na zegarze wyprzedzającym o dwie godziny
2026-08-25T14:30:00Wskazanie zegara, bez chwili
2026-08-25Datę, która trwa 23, 24 albo 25 godzin

Ciąg bez Z i bez przesunięcia jest niejednoznaczny, a parsery się różnią: jedne zakładają UTC, inne strefę systemową. Właśnie dlatego wartość zawierająca samą datę, na przykład data urodzin, renderuje się na zachód od Greenwich często o dzień wcześniej.

Przesunięcie to nie strefa czasowa

+02:00 jest faktem o jednej chwili w jednym miejscu. Europe/Amsterdam to zbiór reguł: +01:00 zimą, +02:00 latem i inny kształt we wcześniejszych dekadach. Przechowywanie przesunięcia zachowuje odpowiedź dla chwili, w której zostało zmierzone, i odbiera możliwość wyliczenia jakiejkolwiek innej.

Przesunięcia nie są też unikalne. W letnie popołudnie +02:00 obejmuje Amsterdam, Lagos i Johannesburg, więc z samego przesunięcia nie ma drogi powrotnej do reguł ani sposobu, żeby wiedzieć, co ten zegar pokaże w grudniu. Skróty są jeszcze gorsze, bo CST nazywa trzy różne strefy. Przechowuj identyfikator IANA w postaci Area/Location.

Godzina, której nie ma, i godzina, która zdarza się dwa razy

W Unii Europejskiej zegary przesuwają się do przodu w ostatnią niedzielę marca i do tyłu w ostatnią niedzielę października. W Amsterdamie 02:00 staje się wiosną 03:00, więc każdy czas lokalny od 02:00:00 do 02:59:59 tego dnia nie występuje. Jesienią 03:00 staje się 02:00, więc 02:30 zdarza się dwa razy, raz przy +02:00 i ponownie godzinę później przy +01:00.

  • Cykliczne alarmy. Zadanie ustawione na 02:30 czasu lokalnego nie ma poprawnego czasu w wiosenną niedzielę. Harmonogramy zachowują się różnie: pomijają je, przesuwają na 03:00 albo przesuwają na 01:30. W jesienną niedzielę to samo zadanie może odpalić raz albo dwa razy, więc sprawdź kilka najbliższych terminów parserem cron.
  • Pliki logów. Godziny lokalnych znaczników czasu bez przesunięcia nie da się posortować, a dwa zdarzenia oddalone o godzinę niosą identyczny tekst. Loguj w UTC albo umieszczaj przesunięcie w każdym wierszu.
  • Czasy trwania. Od 20:00 dnia 24 października 2026 do 20:00 następnego dnia, czasu lokalnego w Amsterdamie, mija 25 godzin. "Dodaj jeden dzień" i "dodaj 24 godziny" to różne operacje, a różnica dat w dniach kalendarzowych odpowiada na inne pytanie niż konwerter czasu trwania pracujący w godzinach.

Reguły się zmieniają, więc sposób przechowywania musi to przetrwać

Baza stref czasowych IANA, tzdata, przechowuje te reguły i jest publikowana kilka razy w roku, ponieważ reguły są aktami prawnymi: rządy znoszą czas letni, wprowadzają go albo przesuwają daty zmiany, czasem z kilkutygodniowym wyprzedzeniem. Przypięty obraz kontenera, przeglądarka i środowisko uruchomieniowe języka niosą każde własną kopię i mogą być ze sobą niezgodne na jednej maszynie. Przeliczenie przyszłego czasu lokalnego na chwilę jest prognozą, rozstrzygniętą dopiero wtedy, gdy ta chwila nadejdzie.

Rodzaj wartościPrzechowujPowód
Coś, co się wydarzyłoChwilę w UTCPrzeszłości nie da się na nowo uchwalić
Przyszłe spotkanie według zegaraLokalną datę i godzinę plus identyfikator strefy IANAIntencją jest wskazanie zegara
Przyszłą chwilę, stałą we wszystkich strefachUTCIntencją jest chwila
Datę bez godzinyZwykłą datę, bez strefy, bez północyDoczepienie strefy powoduje dryf

Właśnie dlatego "po prostu przechowuj UTC" jest błędne przy spotkaniu za rok. Przelicz dziś godzinę 09:00 dnia 30 marca 2027 w strefie Europe/Amsterdam na UTC, a odpowiedzią będzie 07:00Z. Jeśli do tego czasu data zmiany czasu się przesunie, spotkanie nadal będzie o 09:00 czasu lokalnego, ale 07:00Z renderuje się teraz jako 08:00: zapisana wartość zamroziła prognozę i porzuciła intencję. Trzymaj jako źródło prawdy czas lokalny plus strefę; każda kolumna z UTC obok jest tylko pamięcią podręczną.

Pokazywanie dat ludziom

03/04 nie da się jednoznacznie odczytać z samego ciągu znaków. Dla większości świata to 3 kwietnia, a w Stanach Zjednoczonych 4 marca; 03/04/05 dokłada trzecią niewiadomą. Do wyjścia dla człowieka zapisuj miesiąc słowem (4 Apr 2026), a do wymiany maszynowej używaj ISO. Znacznik czasu Discorda omija ten problem w czacie, renderując wartość w strefie i ustawieniach regionalnych tego, kto czyta: przechowuj wartość jednoznaczną, a formatuj na brzegu systemu.

Numery tygodni mają własną regułę. Tygodnie ISO zaczynają się w poniedziałek, a tydzień 1 to ten, który zawiera pierwszy czwartek stycznia, czyli równoważnie ten, który zawiera 4 stycznia. Dlatego 1 stycznia może wypaść w tygodniu 52 albo 53 poprzedniego roku ISO, a 29 grudnia w tygodniu 1 następnego. Częsta konwencja północnoamerykańska numeruje zamiast tego od tygodnia zaczynającego się w niedzielę i zawierającego 1 stycznia, więc ta sama data dostaje dwa numery, a tydzień ISO z kalkulatora dni tygodnia warto zestawić z arkuszem kalkulacyjnym.

Czasy trwania, miesiące i lata przestępne

"Miesiąc później" nie jest stałą liczbą dni; to 28, 29, 30 albo 31. Dodanie miesiąca do 31 stycznia nie ma poprawnej odpowiedzi, a biblioteki zwykle przycinają wynik do końca lutego, co czyni tę operację nieodwracalną: dodaj miesiąc, odejmij go z powrotem, a 31 stycznia jest teraz 28 stycznia. Zaokrąglanie to ta sama pułapka w miniaturze: obcięcie czasu do najbliższego kwadransa i zaokrąglenie do niego różnią się nawet o pełny interwał.

Pełna reguła roku przestępnego: rok jest przestępny, jeśli dzieli się przez 4, z wyjątkiem lat podzielnych przez 100, które przestępne nie są, chyba że dzielą się także przez 400. Zatem rok 1900 przestępny nie był, rok 2000 był, a rok 2100 nie będzie, co daje średni rok długości 365,2425 dnia. Kod sprawdzający wyłącznie podzielność przez 4 jest poprawny dla każdego roku pamiętanego przez żyjących i dlatego przetrwa aż do roku 2100. Pokrewnym utrapieniem jest rocznica przypadająca 29 lutego: kolejny rok oferuje 28 lutego i 1 marca, a żadna reguła nie wybiera między nimi, więc wybierz świadomie.