Na czym polegają problemy z zapisem czasu w informatyce?

Rok 2022 zaczął się od masowych awarii serwera pocztowego Microsoft Exchange, który nie poradził sobie z nową datą. Niedawno problemy z datami miało PKP. W Stanach Zjednoczonych właśnie trwa batalia prawna o zniesienie zmiany czasu. Dlaczego zapis daty i godziny to dalej taki problem?

Ostatni duży, medialny problem związany z zapisem daty to oczywiście Problem Roku 2000 (Y2K), napompowany do postaci czyhającego bezlitośnie końca świata. Wskutek tytanicznej pracy dziesiątek tysięcy inżynierów, problem 2YK udało się zniwelować. Jak to zwykle bywa z rozwiązanymi problemami, doprowadziło to do reakcji “za co my wam tak naprawdę płacimy” oraz całkowitej erozji wiary w jakiekolwiek problemy z czasem opisywane w mediach.

Obecnie na trudności z zapisem dat mogą się natknąć użytkownicy Excela, u których np. zapis “1. Jan Kowalski” bywa w razie nieuwagi konwertowany na pierwszego stycznia. Excel sprawia więcej problemów, ale całkiem niemałą ich liczbę przy okazji rozwiązuje, więc wystarczy odrobina ostrożności, by nie mieć kłopotów.

Poza tym – spokój. No bo na czym miałby polegać problem? Ostatni godny uwagi licznik “przekręcił” się 22 lata temu, więc do roku 3000 (lub 10000!) powinniśmy chyba mieć urlop od awarii związanych z datowaniem. Niestety – to tak nie działa. Po pierwsze dlatego, że “liczników”, które mogą się przekręcić jest więcej. A po drugie, implementując pewne skomplikowane rzeczy od zera (co wciąż ma miejsce bardzo często), można popełnić na nowo dawno rozwiązane już problemy.

Integer overflow

Zacznijmy od przekręcających się liczników. Na pierwszy natknęliśmy się właśnie w tym roku z Exchange, a polegał on na osobliwym wykorzystaniu zmiennej w formacie 32-bitowej liczby całkowitej (signed long integer). Jej maksymalna wartość to 2 to potęgi 31, czyli 2147483647 licząc od zera. Jeżeli wykorzysta się ją do zapisu czasu w postaci YYMMDDHHmm, z początkiem bieżącego roku data zacznie wskazywać 51-szy dzień 52-go miesiąca roku 2000, i godzinę 63:54. Doprowadziło to do błędu konwersji i awarii serwera pocztowego.

Następny w kolejności jest rok 2038 i UNIX, który także używa typu signed long integer, ale tym razem do zapisu daty w postaci liczby sekund, które upłynęły od 1 stycznia 1970. Zmienna ta osiąga maksymalną wartość 19 stycznia 2038 roku, kiedy to 32-bitowe systemy uniksowe (bez nowoczesnych mitygacji) dokonają podróży w czasie i zaczną na zegarach wskazywać godzinę 20:45 dnia 13 grudnia 1901 roku.

Podobnych problemów jest więcej, ale na mniejszą skalę. System Nucleus RTOS potrafi trzymać datę wyłącznie do 2030 roku. Protokół NTP, zaprojektowany specjalnie do przesyłania… czasu, przekręca się w roku 2036 (większość implementacji nie będzie mieć z tym problemu). Konsola Nintendo 3DS uszkodzi wszystkie sejwy polegające na czasie po 1 stycznia 2051 roku. I tak dalej.

Powyższe hece wynikają ze słabości implementacji, opartych o domniemane przekonanie “przecież do tego czasu nikt nie będzie tego używał”. Wiele systemów powstaje z założeniem nadejścia “następcy”, pozbawionego problemów doraźnie bezbolesnych w pierwszej wersji. Gdy jakieś rozwiązanie staje się powszechnym standardem de facto, na poprawki jest za późno i problem zostaje unieśmiertelniony. Dlatego o przekręcającym się liczniku daty np. w GPS przyjdzie nam pamiętać nie tylko za 16 lat, ale i w roku 2137.

Samodzielne implementacje

Pozostaje także kwestia nowych implementacji. Tworząc własną obsługę czasu, trzeba pamiętać nie tylko o kwestiach stałych, jak liczba dni w roku, miesiącu i tygodniu. Dochodzą też bowiem kwestie ruchome, jak lata przestępne i stulecia przestępne (warto pamiętać o obu), a także zmiany czasu na letni/zimowy, które nie wszędzie zachodzą o tej samej porze! Istnieją nie tylko miejsca, które nie stosują zmian czasu. Jest także sporo regionów przesuwających wskazówki zegarów w innych dniach niż my. I mowa tu o całkiem sporych miejscach, a nie terytoriach spornych na Pacyfiku. Na przykład Stany Zjednoczone zmieniają czas dwa tygodnie przed nami.

Zakładając jednak, że uchwycimy wszystkie te detale zarządzania czasem poprawnie, w dalszym ciągu na własnej implementacji obsługi czasu możemy wyjść bardzo źle. Poprawne wyświetlanie czasu teraźniejszego oraz (względna) odporność na najbliższą przyszłość nie oznaczają bowiem jeszcze zgodności z przeszłością.

A co warto mieć na uwadze, operacje arytmetyczne na datach mogą skutkować obliczeniami w zakresie podczas którego nastąpiła np. zmiana strefy czasowej. Zmiany te wcale nie są rzadkie! Archiwum pakietów tzdata pokazuje nam, jak często wydawane są nowe paczki z opisami stref czasowych. Zawierają one także “historię” tego między jakimi strefami przechodziły dane obszary.

Rozwiązanie dla chętnych

Uwzględnienie tych szczegółów jest niezbędne jeżeli chcemy być bardzo dokładni i jest jednym z powodów, dla których stosowany jest czas UTC. Jest on odporny na podróże po strefach czasowych, operacje na wysokich zakresach i zmiany czasu na letni/zimowy. Systemy uniksowe generalnie ustawiają sprzętowy zegar na UTC, a eksponują czas przepuszczony przez strefę czasową zdefiniowaną względem UTC.

Windows robi inaczej. Windows ustawia sprzętowy zegar na czas lokalny, prowadząc do rozjazdów między systemami (podobny kłopot zachodzi z Apple BootCamp). Wynika to ze zgodności z MS-DOS, który prosił użytkownika o czas lokalny i przepisywał tenże na RTC. A więc poza dobrą implementacją czasu (a Windows NT jest bardzo odporny na “przekręcanie licznika” i temu podobne) i poprawną definicją stref czasowych, konieczna jest także wola (lub możliwość!) rzeczywistego wykorzystania tej implementacji

Tagi:

Podziel się postem :)

Najnowsze:

Oprogramowanie

Zmiany w Gmailu. Wyszukiwarka staje się “inteligentniejsza”

Google wprowadza zmiany w swoich usługach, w tym w wyszukiwarce działającej w Gmailu. W praktyce chodzi o rozszerzenie zmian z zapowiedzi, która pojawiła się już w lipcu tego roku. Gmail będzie teraz sprawniej szukać wiadomości zależnie od poprzednich działań użytkownika.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *