Czas systemu Unix składa się z dwóch warstw kodowania. Pierwsza warstwa koduje punkt w czasie jako skalarną liczbę rzeczywistą, która reprezentuje liczbę sekund, które upłynęły od 00:00:00 UTC w czwartek, 1 stycznia 1970 roku. Druga warstwa koduje tę liczbę jako sekwencję bitów lub cyfr dziesiętnych.
Jak jest standardem w UTC, ten artykuł etykietuje dni za pomocą kalendarza gregoriańskiego i liczy czasy w ciągu każdego dnia w godzinach, minutach i sekundach. Niektóre przykłady pokazują również Międzynarodowy Czas Atomowy (TAI), inny schemat czasowy, który używa tych samych sekund i jest wyświetlany w tym samym formacie co UTC, ale w którym każdy dzień ma dokładnie 86400 sekund długości, stopniowo tracąc synchronizację z ruchem obrotowym Ziemi w tempie około jednej sekundy na rok.
Kodowanie czasu jako liczbyEdit
Czas systemu Unix jest pojedynczą podpisaną liczbą, która zwiększa się co sekundę, co sprawia, że jest łatwiejsza do przechowywania i manipulowania przez komputery niż konwencjonalne systemy dat. Programy interpretujące mogą następnie przekonwertować go na format czytelny dla człowieka.
Epoka systemu Unix to czas 00:00:00 UTC 1 stycznia 1970 roku. Istnieje problem z tą definicją, ponieważ UTC nie istniał w swojej obecnej formie do 1972 roku; ta kwestia jest omówiona poniżej. Dla zwięzłości, pozostała część tej sekcji używa formatu daty i czasu ISO 8601, w którym epoka Uniksa to 1970-01-01T00:00:00Z.
Liczba czasu Uniksa wynosi zero w epoce Uniksa i zwiększa się dokładnie o 86400 na dzień od epoki. Tak więc 2004-09-16T00:00:00Z, 12677 dni po epoce, jest reprezentowane przez uniksowy numer czasu 12677 × 86400 = 1095292800. Można to również rozszerzyć wstecz od epoki, używając liczb ujemnych; tak więc 1957-10-04T00:00:00Z, 4472 dni przed epoką, jest reprezentowane przez uniksową liczbę czasową -4472 × 86400 = -386380800. Dotyczy to również dni; numer czasu w dowolnym momencie dnia jest liczbą sekund, które upłynęły od północy rozpoczynającej ten dzień, dodaną do numeru czasu tej północy.
Ponieważ czas systemu Unix jest oparty na epoce i z powodu powszechnego nieporozumienia, że epoka systemu Unix jest jedyną epoką (często nazywaną „epoką”), czas systemu Unix jest czasami określany jako czas epoki.
Sekundy przestępneEdit
Powyższy schemat oznacza, że w normalnym dniu UTC, który ma czas trwania 86400 sekund, numer czasu uniksowego zmienia się w sposób ciągły przez północ. Na przykład, pod koniec dnia używanego w powyższych przykładach, reprezentacje czasu postępują w następujący sposób:
Gdy występuje sekunda przestępna, dzień UTC nie ma dokładnie 86400 sekund długości, a numer czasu Unix (który zawsze wzrasta o dokładnie 86400 każdego dnia) doświadcza nieciągłości. Sekundy przestępne mogą być dodatnie lub ujemne. Żadna ujemna sekunda przestępna nigdy nie została zadeklarowana, ale gdyby taka była, to na koniec dnia z ujemną sekundą przestępną, uniksowy numer czasu podskoczyłby o 1 do początku następnego dnia. Podczas dodatniej sekundy przestępnej na koniec dnia, która występuje średnio co półtora roku, liczba czasu Uniksa wzrasta w sposób ciągły do następnego dnia podczas sekundy przestępnej, a następnie na końcu sekundy przestępnej przeskakuje z powrotem o 1 (wracając do początku następnego dnia). Na przykład, tak się stało w systemach POSIX.1 ściśle zgodnych z POSIX.1 pod koniec 1998 roku:
Uniksowe numery czasu są powtarzane w sekundzie następującej bezpośrednio po dodatniej sekundzie przestępnej. Unixowa liczba czasowa 1483142400 jest więc niejednoznaczna: może odnosić się albo do początku sekundy przestępnej (2016-12-31 23:59:60) albo do jej końca, sekundę później (2017-01-01 00:00:00). W teoretycznym przypadku, gdy występuje ujemna sekunda przestępna, nie ma dwuznaczności, ale zamiast tego istnieje zakres numerów czasu systemu Unix, które nie odnoszą się do żadnego punktu w czasie UTC w ogóle.
Zegar systemu Unix jest często implementowany z innym typem obsługi dodatniej sekundy przestępnej związanej z protokołem Network Time Protocol (NTP). Daje to system, który nie jest zgodny ze standardem POSIX. Zobacz poniższą sekcję dotyczącą NTP po szczegóły.
Gdy mamy do czynienia z okresami, które nie obejmują sekundy przestępnej UTC, różnica między dwoma numerami czasu Unix jest równa czasowi trwania w sekundach okresu między odpowiednimi punktami w czasie. Jest to powszechnie stosowana technika obliczeniowa. Jednak tam, gdzie występują sekundy przestępne, takie obliczenia dają błędną odpowiedź. W aplikacjach, gdzie wymagany jest ten poziom dokładności, konieczne jest sprawdzenie tabeli sekund przestępnych podczas pracy z czasami uniksowymi, a często lepiej jest użyć innego kodowania czasu, które nie cierpi z powodu tego problemu.
Liczba czasu uniksowego jest łatwo konwertowana z powrotem na czas UTC, biorąc iloraz i modulus liczby czasu uniksowego, modulo 86400. Iloraz jest liczbą dni od epoki, a moduł jest liczbą sekund od północy UTC w tym dniu. Jeśli podano numer czasu uniksowego, który jest niejednoznaczny z powodu dodatniej sekundy przestępnej, to algorytm ten interpretuje go jako czas tuż po północy. Nigdy nie generuje czasu, który jest podczas sekundy przestępnej. Jeśli podany numer czasu systemu Unix jest nieprawidłowy z powodu ujemnej sekundy przestępnej, to algorytm generuje równie nieprawidłowy czas UTC. Jeśli te warunki są istotne, konieczne jest sprawdzenie tabeli sekund przestępnych w celu ich wykrycia.
Niesynchroniczny wariant oparty na Network Time ProtocolEdit
Często zegar uniksowy w stylu Mills jest zaimplementowany z obsługą sekund przestępnych niezsynchronizowaną ze zmianą uniksowego numeru czasu. Numer czasu początkowo zmniejsza się tam, gdzie powinien nastąpić przeskok, a następnie przeskakuje do prawidłowego czasu 1 sekundę po przeskoku. Ułatwia to implementację i jest opisane w artykule Millsa. Oto co się dzieje w przypadku dodatniej sekundy przeskoku:
Można to poprawnie zdekodować zwracając uwagę na zmienną stanu leap second, która jednoznacznie wskazuje, czy przeskok został już wykonany. Zmiana zmiennej stanu jest synchroniczna z przeskokiem.
Podobna sytuacja występuje przy ujemnej sekundzie przeskoku, gdzie pominięta sekunda jest nieco za późno. Bardzo krótko system pokazuje nominalnie niemożliwy numer czasu, ale może to być wykryte przez stan TIME_DEL i poprawione.
W tego typu systemie uniksowy numer czasu narusza POSIX wokół obu typów sekund przestępnych. Zbieranie zmiennej stanu sekundy przestępnej wraz z numerem czasu pozwala na jednoznaczne dekodowanie, więc poprawny POSIX-owy numer czasu może być wygenerowany, jeśli jest to pożądane, lub pełny czas UTC może być przechowywany w bardziej odpowiednim formacie.
Logika dekodowania wymagana do radzenia sobie z tym stylem zegara uniksowego również poprawnie dekodowałaby hipotetyczny zegar zgodny z POSIX-em używając tego samego interfejsu. Zostałoby to osiągnięte przez wskazanie stanu TIME_INS podczas całej wstawionej sekundy przestępnej, a następnie wskazanie TIME_WAIT podczas całej następnej sekundy, powtarzając jednocześnie liczenie sekund. Wymaga to synchronicznej obsługi sekund przestępnych. Jest to prawdopodobnie najlepszy sposób na wyrażenie czasu UTC w formie zegara uniksowego, poprzez interfejs uniksowy, gdy zegar bazowy jest zasadniczo niezakłócony przez sekundy przestępne.
Wariant oparty na TAIEdit
Inny, znacznie rzadszy, niezgodny z normami wariant utrzymywania czasu uniksowego obejmuje kodowanie TAI zamiast UTC; niektóre systemy linuksowe są skonfigurowane w ten sposób. Ponieważ TAI nie ma sekund przestępnych, a każdy dzień TAI ma dokładnie 86400 sekund długości, to kodowanie jest w rzeczywistości czystą liniową liczbą sekund, które upłynęły od 1970-01-01T00:00:00 TAI. To czyni arytmetykę przedziałów czasowych znacznie łatwiejszą. Wartości czasu z tych systemów nie cierpią na niejednoznaczność, którą mają ściśle zgodne systemy POSIX lub systemy napędzane przez NTP.
W tych systemach konieczne jest skonsultowanie tabeli sekund przestępnych, aby poprawnie przekonwertować między UTC i reprezentacją czasu pseudo-Unix. Przypomina to sposób, w jaki tabele stref czasowych muszą być konsultowane w celu konwersji do i z czasu cywilnego; baza stref czasowych IANA zawiera informacje o sekundach przestępnych, a przykładowy kod dostępny z tego samego źródła używa tych informacji do konwersji między znacznikami czasu opartymi na TAI a czasem lokalnym. Konwersja również napotyka na problemy definicyjne przed rozpoczęciem w 1972 roku obecnej formy UTC (patrz sekcja Podstawa UTC poniżej).
Ten system oparty na TAI, pomimo powierzchownego podobieństwa, nie jest czasem uniksowym. Koduje on czasy z wartościami różniącymi się o kilka sekund od wartości czasu POSIX. Wersja tego systemu została zaproponowana do włączenia do ISO C’s time.h
, ale tylko część UTC została zaakceptowana w 2011 roku. A tai_clock
istnieje jednak w C++20.
Reprezentowanie liczbyEdit
Uniksowa liczba czasu może być reprezentowana w dowolnej formie zdolnej do reprezentowania liczb. W niektórych zastosowaniach liczba jest po prostu reprezentowana tekstowo jako ciąg cyfr dziesiętnych, co stwarza tylko trywialne dodatkowe problemy. Jednak niektóre binarne reprezentacje czasów uniksowych są szczególnie istotne.
Uniksowy time_t
typ danych, który reprezentuje punkt w czasie, jest na wielu platformach podpisaną liczbą całkowitą, tradycyjnie 32-bitową (ale zobacz poniżej), bezpośrednio kodującą uniksowy numer czasu, jak opisano w poprzedniej sekcji. 32 bity oznaczają, że obejmuje ona zakres około 136 lat w sumie. Minimalną reprezentowalną datą jest piątek 1901-12-13, a maksymalną reprezentowalną datą jest wtorek 2038-01-19. Jedna sekunda po 03:14:07 UTC 2038-01-19 ta reprezentacja będzie przepełniona. Ten kamień milowy jest oczekiwany z mieszaniną rozbawienia i strachu – patrz rok 2038 problem.
W niektórych nowszych systemach operacyjnych, time_t
został rozszerzony do 64 bitów. To rozszerza czasy reprezentowalne o około 293 miliardy lat w obu kierunkach, co jest ponad dwudziestokrotnością obecnego wieku wszechświata w każdym kierunku.
Początkowo istniały pewne kontrowersje dotyczące tego, czy uniksowy time_t
powinien być podpisany czy niepodpisany. Jeśli bez znaku, jego zasięg w przyszłości zostałby podwojony, odraczając 32-bitowe przepełnienie (o 68 lat). Jednakże, nie byłby wtedy zdolny do reprezentowania czasów przed epoką. Konsensus jest taki, że time_t
powinien być podpisany i jest to powszechna praktyka. Platforma programistyczna dla wersji 6 systemu operacyjnego QNX ma niepodpisany 32-bitowy time_t
, choć starsze wydania używały podpisanego typu.
Specyfikacje POSIX i Open Group Unix zawierają bibliotekę standardową C, która zawiera typy czasowe i funkcje zdefiniowane w pliku nagłówkowym <time.h>
. Standard ISO C stwierdza, że time_t
musi być typem arytmetycznym, ale nie nakazuje żadnego konkretnego typu lub kodowania dla niego. POSIX wymaga, by time_t
był typem całkowitym, ale nie nakazuje, by był on podpisany lub niepodpisany.
Unix nie ma tradycji bezpośredniego reprezentowania nie-jednocyfrowych liczb czasu Uniksa jako ułamków binarnych. Zamiast tego czasy o dokładności poniżej sekundy są reprezentowane za pomocą złożonych typów danych, które składają się z dwóch liczb całkowitych, z których pierwsza jest time_t
(integralna część czasu Uniksa), a druga jest ułamkową częścią liczby czasu w milionowych częściach (w struct timeval
) lub miliardowych (w struct timespec
). Struktury te zapewniają dziesiętny format danych stałoprzecinkowych, który jest przydatny dla niektórych zastosowań, a trywialny do konwersji dla innych.
Podstawa UTCEdit
Obecna forma UTC, z sekundami przestępnymi, jest zdefiniowana tylko począwszy od 1 stycznia 1972 roku. Wcześniej, od 1 stycznia 1961 roku istniała starsza forma UTC, w której nie tylko występowały sporadyczne kroki czasowe, które były o nie-liczbowe sekundy, ale także sekunda UTC była nieco dłuższa niż sekunda SI i okresowo zmieniana w celu ciągłego przybliżenia obrotu Ziemi. Przed 1961 rokiem nie było UTC, a przed 1958 rokiem nie było rozpowszechnionego atomowego pomiaru czasu; w tych epokach, pewne przybliżenie GMT (oparte bezpośrednio na ruchu obrotowym Ziemi) było używane zamiast atomowej skali czasu.
Precyzyjna definicja czasu Uniksa jako kodowania UTC jest niekontrowersyjna tylko wtedy, gdy jest stosowana do obecnej formy UTC. Epoka Uniksa poprzedzająca początek tej formy UTC nie wpływa na jej użycie w tej erze: liczba dni od 1 stycznia 1970 (epoka Uniksa) do 1 stycznia 1972 (początek UTC) nie jest kwestionowana, a liczba dni jest wszystkim, co jest istotne dla czasu Uniksa.
Znaczenie wartości czasu Uniksa poniżej +63072000 (tj. przed 1 stycznia 1972) nie jest dokładnie określone. Podstawę takich czasów uniksowych najlepiej rozumieć jako nieokreślone przybliżenie UTC. Komputery z tamtej epoki rzadko miały zegary ustawione wystarczająco dokładnie, aby zapewnić znaczące sub-sekundowe znaczniki czasu w każdym przypadku. Czas uniksowy nie jest odpowiednim sposobem na reprezentowanie czasów sprzed 1972 roku w aplikacjach wymagających sub-sekundowej precyzji; takie aplikacje muszą przynajmniej określić, której formy UT lub GMT używają.
Od 2009 roku rozważana jest możliwość zakończenia używania sekund przestępnych w czasie cywilnym. Prawdopodobnym sposobem wykonania tej zmiany jest zdefiniowanie nowej skali czasu, zwanej czasem międzynarodowym, która początkowo odpowiada UTC, ale później nie ma sekund przestępnych, pozostając w ten sposób w stałym przesunięciu od TAI. Jeśli tak się stanie, jest prawdopodobne, że czas uniksowy będzie prospektywnie definiowany w kategoriach tej nowej skali czasu, zamiast UTC. Niepewność co do tego, czy tak się stanie, sprawia, że przyszły czas uniksowy nie jest mniej przewidywalny niż jest teraz: jeśli UTC po prostu nie miałby więcej sekund przestępnych, wynik byłby taki sam.