Czas i język systemu
Po tej lekcji: kursant ustawia strefę czasową i synchronizację zegara (timedatectl, chrony), czyta chronyc tracking i chronyc sources, rozumie różnicę między zegarem systemowym a sprzętowym (hwclock) oraz ustawia język i format danych systemu (localectl, locale, LANG), wiedząc, jak to wpływa na skrypty.
Wstęp
Awaria. Aplikacja na jednym serwerze, baza na drugim. Porównujesz logi, żeby zobaczyć, co było pierwsze. I nic się nie składa: według logów baza odpowiedziała na zapytanie siedem minut przed tym, zanim aplikacja je wysłała. Albo baza ma moce jasnowidzenia, albo zegary się rozjechały.
Zły zegar to nie kosmetyka. Certyfikaty z poprzedniej lekcji mają daty ważności. Jak zegar jest do tyłu, certyfikat wygląda na „jeszcze nieważny”. Jak do przodu, na „już wygasły”. Logowanie do domeny Active Directory z lekcji 81 opiera się na Kerberosie, który nie wpuści nikogo, kto ma zegar rozjechany o kilka minut. Dziś ustawiamy czas raz, porządnie, i przy okazji język systemu, który potrafi po cichu popsuć skrypty.
Dwa zegary w jednym komputerze
W komputerze są dwa zegary. Pierwszy to zegarek na ręce: zegar sprzętowy, RTC (Real Time Clock). Mała kostka na płycie głównej z baterią, chodzi nawet przy wyłączonym komputerze. Drugi to zegar ścienny w biurze: zegar systemowy, który prowadzi jądro. Przy starcie system patrzy na zegarek na ręce i ustawia według niego zegar ścienny. Potem już każdy chodzi swoim tempem i oba się spieszą albo spóźniają. Zwykły kwarc myli się o kilka sekund dziennie.
Dlatego jest trzecia rzecz: NTP, Network Time Protocol. To dzwonienie na zegarynkę. System co jakiś czas pyta serwery czasu w internecie, która jest godzina, i delikatnie poprawia swój zegar.
Zegar sprzętowy podglądasz przez hwclock:
sudo hwclock --show # co mówi zegarek na ręce
sudo hwclock --systohc # przestaw zegarek na ręce według ściennego
sudo hwclock --hctosys # przestaw ścienny według zegarka na ręcesystohc czytaj „system to hardware clock”, hctosys odwrotnie. Na maszynie wirtualnej albo w kontenerze często zobaczysz tylko:
hwclock: Cannot access the Hardware Clock via any known method.I to normalne, maszyna nie ma własnej kostki zegara albo nie wolno jej jej dotykać. Wtedy czasem rządzi gospodarz.
Strefa czasowa: timedatectl
Komputer w środku liczy czas jednakowo dla całego świata: w UTC, czasie uniwersalnym, bez zmian na letni i zimowy. Strefa czasowa to tylko okulary, przez które ten czas wyświetla. Ten sam moment wygląda tak:
TZ=UTC date -d @1793750400
TZ=Europe/Warsaw date -d @1793750400
TZ=America/New_York date -d @1793750400
TZ=Asia/Tokyo date -d @1793750400Wed Nov 4 00:00:00 UTC 2026
Wed Nov 4 01:00:00 CET 2026
Tue Nov 3 19:00:00 EST 2026
Wed Nov 4 09:00:00 JST 2026Jedna liczba sekund od 1970 roku, cztery różne godziny na ścianie. Zmienna TZ zmienia okulary tylko dla jednej komendy. Dla całego systemu służy timedatectl:
timedatectl
timedatectl list-timezones | grep Europe/W
sudo timedatectl set-timezone Europe/Warsaw Local time: Tue 2026-11-03 22:15:51 CET
Universal time: Tue 2026-11-03 21:15:51 UTC
RTC time: Tue 2026-11-03 21:15:50
Time zone: Europe/Warsaw (CET, +0100)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no(Układ pól jak w dokumentacji Red Hata, u Ciebie będą inne godziny.) Czytamy: czas lokalny, czas uniwersalny, czas zegarka na ręce, strefa. System clock synchronized: yes znaczy, że zegarynka odpowiada. NTP service: active, że ktoś do niej dzwoni. A RTC in local TZ: no to dobra wiadomość: zegar sprzętowy trzyma czas w UTC. Tak ma być na serwerze.
Pod spodem set-timezone robi jedną prostą rzecz: przestawia dowiązanie /etc/localtime na plik strefy z /usr/share/zoneinfo:
ls -l /etc/localtimelrwxrwxrwx 1 root root 35 ... /etc/localtime -> ../usr/share/zoneinfo/Europe/Warsaw[Ubuntu] Na Ubuntu jest jeszcze tekstowy /etc/timezone i kreator sudo dpkg-reconfigure tzdata, ale timedatectl załatwia wszystko.
Czy serwery trzymać w czasie lokalnym, czy w UTC? W wielu firmach serwery chodzą w UTC, żeby logi z Warszawy, Dublina i Singapuru dało się położyć obok siebie. Jedno jest pewne: wszystkie serwery jednego systemu w tej samej strefie. Inaczej wracamy do bazy-jasnowidza z haka.
Zmiana czasu: zegar, który przeskakuje
Strefa Europe/Warsaw zna nasze zmiany czasu. Popatrz, co się dzieje w nocy 29 marca 2026:
zdump -v Europe/Warsaw | grep 2026Europe/Warsaw Sun Mar 29 00:59:59 2026 UT = Sun Mar 29 01:59:59 2026 CET isdst=0 gmtoff=3600
Europe/Warsaw Sun Mar 29 01:00:00 2026 UT = Sun Mar 29 03:00:00 2026 CEST isdst=1 gmtoff=7200
Europe/Warsaw Sun Oct 25 00:59:59 2026 UT = Sun Oct 25 02:59:59 2026 CEST isdst=1 gmtoff=7200
Europe/Warsaw Sun Oct 25 01:00:00 2026 UT = Sun Oct 25 02:00:00 2026 CET isdst=0 gmtoff=3600Po 01:59:59 przychodzi od razu 03:00:00. Godzina 02:30 tej nocy po prostu nie istnieje. A w październiku godzina od 02:00 do 03:00 zdarza się dwa razy. Zapamiętaj to sobie na następna lekcja o cronie. Zadanie ustawione na 02:30 potrafi raz w roku nie odpalić się wcale, a raz w roku się zdublować. Kolejny powód, żeby poważne serwery chodziły w UTC, które nie zna zmiany czasu.
Synchronizacja: chrony
Teraz zegarynka. Na RHEL od wersji 8 i na Ubuntu od 25.10 domyślnie dzwoni do niej chrony. [Ubuntu] Na Ubuntu 24.04 domyślnie pracuje prostszy systemd-timesyncd. Możesz go zamienić na chrony jedną instalacją, pakiety się wykluczają:
sudo apt install chrony # [Ubuntu], usuwa systemd-timesyncd
sudo dnf install chrony # [RHEL], zwykle już jest
sudo timedatectl set-ntp true
systemctl status chrony # [Ubuntu]
systemctl status chronyd # [RHEL]Zwróć uwagę na nazwy: na Ubuntu usługa to chrony, na RHEL chronyd. Plik ustawień: /etc/chrony/chrony.conf na Ubuntu, /etc/chrony.conf na RHEL. W środku najważniejsze są linijki z serwerami czasu:
pool ntp.ubuntu.com iburst maxsources 4
pool 0.ubuntu.pool.ntp.org iburst maxsources 1
...
driftfile /var/lib/chrony/chrony.driftpool to grupa serwerów pod jedną nazwą, server to jeden konkretny serwer. iburst znaczy „na starcie zapytaj kilka razy szybko”, żeby zegar złapał synchronizację w sekundy, a nie w minuty. W firmie zamiast publicznych serwerów wpisujesz własny serwer czasu albo kontroler domeny. Po zmianie: sudo systemctl restart chronyd (albo chrony na Ubuntu).
I dwie komendy, które musisz znać. Czy zegar jest dobry?
chronyc trackingReference ID : 7F000001 (localhost)
Stratum : 9
Ref time (UTC) : Tue Nov 03 21:14:37 2026
System time : 0.000002805 seconds fast of NTP time
Last offset : +0.000000076 seconds
RMS offset : 0.000006855 seconds
Frequency : 0.014 ppm fast
...
Update interval : 5.1 seconds
Leap status : NormalTo prawdziwy wynik z mojego laboratorium, w którym jeden chrony udawał serwer czasu dla drugiego. U Ciebie zamiast localhost będzie nazwa albo adres serwera z internetu. Najważniejsze linijki:
Reference ID— z kim się synchronizujesz.Stratum— ile pięter od wzorca. Stratum 1 to serwer podłączony bezpośrednio do zegara atomowego albo GPS. Każdy kolejny serwer w łańcuchu dodaje jedno piętro. 9 w laboratorium, w internecie zwykle 2 albo 3.System time— o ile Twój zegar się teraz myli. Tu: niespełna 3 mikrosekundy. Można z tym żyć.Frequency— jak bardzo Twój kwarc się spieszy albo spóźnia, w milionowych częściach. chrony to zapamiętuje w pliku drift i poprawia na bieżąco.Leap status: Normal— synchronizacja działa.Not synchronisedznaczy kłopoty.
A z kim rozmawiasz?
chronyc sources -vMS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^* localhost 8 0 377 3 +6500ns[+6576ns] +/- 10us^ to serwer, * to „ten aktualnie wybrany jako najlepszy”. + przy innych to „używany pomocniczo”, ? to „nie odpowiada”. Kolumna Reach to ósemkowy zapis ostatnich ośmiu prób: 377 znaczy, że wszystkie osiem się udało. 0 znaczy, że zegarynka milczy. Wtedy pierwsze podejrzenie: zapora blokuje wychodzący UDP na porcie 123. Opcja -v dopisuje nad tabelą legendę wszystkich znaczków, więc nie musisz tego wkuwać.
chrony poprawia zegar łagodnie: trochę przyspiesza albo zwalnia, zamiast przeskakiwać, żeby czas w logach nie cofał się nagle. Jeśli zegar jest rozjechany o godziny, możesz kazać skoczyć od razu: sudo chronyc makestep.
Język i format: locale
Teraz druga połowa lekcji. Locale to zestaw ustawień regionalnych: język komunikatów, format daty, przecinek czy kropka w liczbach, kolejność sortowania liter. Jak tłumacz z kompletem przyzwyczajeń danego kraju.
locale
locale -aLANG=pl_PL.UTF-8
LANGUAGE=
LC_CTYPE="pl_PL.UTF-8"
LC_NUMERIC="pl_PL.UTF-8"
...
C
C.utf8
en_US.utf8
pl_PL.utf8LANG to ustawienie domyślne. Zmienne LC_* nadpisują pojedyncze dziedziny: LC_TIME daty, LC_NUMERIC liczby, LC_COLLATE sortowanie, LC_MESSAGES język komunikatów. A LC_ALL to młotek, który nadpisuje wszystko naraz. Kolejność ważności: LC_ALL, potem konkretne LC_*, na końcu LANG. C (albo POSIX) to locale „gołe”: angielskie komunikaty, kropka w liczbach, sortowanie po kodach znaków.
Popatrz, jak to samo zmienia wynik:
LC_ALL=C date -d @1793750400
LC_ALL=pl_PL.UTF-8 date -d @1793750400 '+%A, %d %B %Y'
LC_ALL=pl_PL.UTF-8 date +%x
LC_ALL=en_US.UTF-8 date +%xWed Nov 4 01:00:00 CET 2026
środa, 04 listopada 2026
03.11.2026
11/03/2026I sortowanie:
LC_ALL=C sort slowa.txt
LC_ALL=pl_PL.UTF-8 sort slowa.txtAla lis zebra łoś Żaba
Ala lis łoś zebra ŻabaW C polskie litery lądują na końcu, bo mają dalsze kody. W polskim locale łoś stoi grzecznie po lisie. Jak w słowniku.
Ustawienie dla całego systemu:
localectl status
localectl list-locales
sudo localectl set-locale LANG=pl_PL.UTF-8
sudo localectl set-keymap pl[RHEL] Locale zapisuje się w /etc/locale.conf, układ klawiatury konsoli w /etc/vconsole.conf. Brakujące języki doinstalowujesz pakietami: sudo dnf install glibc-langpack-pl. [Ubuntu] Locale leży w /etc/default/locale. Brakujące generujesz: sudo locale-gen pl_PL.UTF-8 albo przez kreator sudo dpkg-reconfigure locales.
Na serwerze wiele osób zostawia LANG=en_US.UTF-8 albo C.UTF-8, nawet w Polsce. Powód prosty: komunikat błędu po angielsku wklejasz w wyszukiwarkę i znajdujesz tysiąc odpowiedzi. Po polsku znajdziesz trzy, w tym jedną swoją sprzed roku.
Jak to działa pod spodem
Jądro trzyma czas jako liczbę sekund (i ułamków) od 1 stycznia 1970 UTC, tak zwaną epokę Uniksa. Nic nie wie o strefach. Zamianą na „środa, 01:00 CET” zajmuje się biblioteka C w każdym programie: czyta zmienną TZ, a jak jej nie ma, plik /etc/localtime. Dlatego zmiana strefy działa od razu dla nowych programów, a długo działające usługi czasem trzeba zrestartować, żeby zauważyły.
chronyd wysyła zapytania NTP po UDP na port 123, mierzy, ile trwała podróż pakietu tam i z powrotem, i z tego liczy, o ile myli się lokalny zegar. Poprawkę przekazuje jądru przez wywołanie systemowe, które każe zegarowi chodzić odrobinę szybciej albo wolniej. timedatectl to tylko pilot do usługi systemd-timedated. set-ntp true włącza tę usługę synchronizacji, którą pakiet zgłosił w /usr/lib/systemd/ntp-units.d/. Na Ubuntu z chrony jest tam plik 50-chrony.list z jedną linijką: chrony.service.
Locale też obsługuje biblioteka C. Program na starcie woła setlocale, ta patrzy w LC_ALL, LC_* i LANG i ładuje skompilowane dane z /usr/lib/locale. Jeśli locale nie ma, program dostaje C i ewentualnie narzeka. O tym narzekaniu za chwilę.
Ściąga flag
| Komenda | Flaga | Co robi |
|---|---|---|
timedatectl | (bez argumentów) | czas, strefa, stan synchronizacji |
timedatectl | list-timezones | lista stref |
timedatectl | set-timezone STREFA | ustawia strefę (/etc/localtime) |
timedatectl | set-ntp true | włącza synchronizację |
timedatectl | set-time 'RRRR-MM-DD GG:MM:SS' | ręczne ustawienie (tylko przy wyłączonym NTP) |
timedatectl | set-local-rtc 0 | RTC w UTC |
chronyc | tracking | jak dobry jest zegar |
chronyc | sources -v | serwery czasu z legendą |
chronyc | sourcestats | statystyki dla źródeł |
chronyc | makestep | natychmiastowy skok zegara |
hwclock | --show / --systohc / --hctosys | odczyt RTC / RTC wg systemu / system wg RTC |
date | -d @SEKUNDY, +FORMAT | zamiana epoki na datę, własny format |
zdump | -v STREFA | przejścia na czas letni/zimowy |
locale | -a | dostępne locale |
localectl | set-locale LANG=... | locale systemu |
localectl | set-keymap pl | układ klawiatury konsoli |
locale-gen | pl_PL.UTF-8 | [Ubuntu] generuje locale |
⚠ Typowy błąd
Dwa klasyki, oba z locale.
Pierwszy: łączysz się z Maca po SSH, robisz apt upgrade i dostajesz ścianę ostrzeżeń:
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LANGUAGE = (unset),
LC_ALL = "de_DE.UTF-8",
...
bash: warning: setlocale: LC_ALL: cannot change locale (de_DE.UTF-8): No such file or directorySkąd niemieckie locale na polskim serwerze? Klient SSH ma w /etc/ssh/ssh_config linijkę SendEnv LANG LC_*, a serwer Ubuntu w sshd_config ma AcceptEnv LANG LC_*. Twój laptop grzecznie przesyła swoje ustawienia regionalne, a serwer grzecznie je przyjmuje, tylko że takiego locale nie ma. Jak gość, który przychodzi do restauracji z własnym menu w języku, którego nie zna kucharz. Naprawa: wygeneruj to locale na serwerze (locale-gen) albo nie wysyłaj go z laptopa.
Drugi, groźniejszy, bo cichy: skrypt działał latami, ktoś zmienił locale serwera na polskie i nagle sumy się nie zgadzają:
LC_ALL=C seq 0.5 0.5 1.5 | awk '{s+=$1} END{print s}'
LC_ALL=pl_PL.UTF-8 seq 0.5 0.5 1.5 | awk '{s+=$1} END{print s}'
LC_ALL=pl_PL.UTF-8 seq 0.5 0.5 1.53
2
0,5
1,0
1,5Polskie locale mówi „u nas ułamki pisze się z przecinkiem”, więc seq wypisuje 0,5. A awk czyta liczby po swojemu, z kropką, i z 0,5 bierze tylko 0. Wynik 2 zamiast 3, bez żadnego błędu. Księgowa by się nie pomyliła, a skrypt tak. Zasada: skrypt, który przetwarza liczby, daty albo wynik innych programów, ustawia sobie na początku export LC_ALL=C. Wtedy działa tak samo na każdym serwerze, niezależnie od tego, kto i jak go skonfigurował.
✎ Zadanie
Ustaw strefę czasową Europe/Warsaw, włącz synchronizację czasu i sprawdź chronyc tracking. Potem sprawdź komendą openssl, do kiedy jest ważny certyfikat strony google.com.
Pokaż rozwiązanie
Strefa czasowa, synchronizacja czasu i sprawdzenie, czy zegar naprawdę chodzi:
sudo timedatectl set-timezone Europe/Warsaw
sudo timedatectl set-ntp true
timedatectl
chronyc trackingW timedatectl patrzysz na dwie linijki: Time zone: Europe/Warsaw (CET, +0100) i System clock synchronized: yes. W chronyc tracking najważniejsze jest Leap status : Normal, czyli „mam z kim gadać i wszystko gra”, oraz System time, czyli o ile Twój zegar różni się od wzorca. Jak tam są milisekundy albo mniej, możesz spać spokojnie. Jak widzisz Not synchronised, to chronyc sources pokaże, czy serwer w ogóle widzi jakiekolwiek źródło czasu.
Druga część, data ważności certyfikatu Google:
openssl s_client -connect google.com:443 -servername google.com </dev/null 2>/dev/null \
| openssl x509 -noout -datesDostajesz dwie linijki: notBefore= i notAfter=. Pierwsza mówi, od kiedy certyfikat jest ważny, druga do kiedy. U Google zobaczysz, że certyfikat żyje krótko, kilka miesięcy. Wielkie firmy wymieniają certyfikaty częściej niż niektórzy z nas szczoteczki do zębów. </dev/null jest po to, żeby s_client nie czekał w nieskończoność, aż coś do niego napiszesz.
I zapamiętaj ten moment: sprawdziłeś to ręcznie. A gdyby tak serwer sam sprawdzał to co noc i pisał do Ciebie, jak zostanie mniej niż dwa tygodnie? Do tego potrzebny jest budzik. I o budziku jest ta lekcja.
Co dalej
Zegar chodzi, strefa ustawiona. Czas to wykorzystać. W następnej lekcji zadania o wyznaczonej godzinie: cron, crontab, at, timery systemd i odwieczna zagadka admina: „skrypt ręcznie działa, a z crona nie”.