Koľko je hodín?

prečo je čas dôležitý v IoT riešeniach, hodiny reálneho času, problém synchronizácie času, Unixový čas, počiatok epochy, NTP protokol, podpora NTP a hodiny reálneho času v mikrokontroléri ESP32

Záznam z prednášky

Príbeh Boeing CST-100 “Starliner”

  • (slide) Po rokoch vývoja sa prvý testovací let kozmickej lode Starliner-u nakoniec uskutočnil. Loď Starliner vzlietla ráno v piatok 20.dec.2019 o 12:36 stredoeurópskeho času z Kennedyho vesmírneho strediska na Floride a jej cieľom bolo spojenie s Medzinárodnou vesmírnou stanicou (ISS) o deň neskôr. Tento let bol bez ľudskej posádky. Loď vynášala raketa Atlas V od United Launch Alliance.

    Boeing CST-100 “Starliner”
  • K tomuto spojeniu však nikdy nedošlo, pretože počas letu došlo naopak k niekoľkým chybám. Raketa Atlas V síce vyniesla Starliner na správnu trajektóriu, problém nastal v samotnej lodi. Podľa oznámenia NASA a Boeingu bola zrejme chyba v systéme počítania času misie. Loď si totiž myslela, že už uskutočnila orbitálny manéver hoci sa tak nestalo a snažila sa udržiavať presnú kontrolu, na čo ale minula veľa paliva.

  • A aby to nebolo všetko, pozemná kontrola sa pokúsila vyriešiť vzniknutú situáciu tým, že posielala lodi príkaz na uskutočnenie spomínaného orbitálneho manévru. Loď však tento príkaz úspešne neprijala a tak jej nezostalo dostatok paliva na úspešné dokončenie celej misie. Nakoniec na ISS neletela. Bola umiestnená na inú orbitu a v nedeľu bezpečne pristála na Zemi.

  • Celý problém teda začal zlyhaním interného časovača misie, ktorý sa skrátene označuje ako MET (Mission Event Timer). Tento časovač sa za normálnych okolností spustí hneď potom, ako loď opustí štartovaciu rampu a používa sa na orchestráciu automatizovaných systémov počas priebehu misie. A keďže MET buď úplne zlyhal alebo nebol dobre zosynchronizovaný, motory sa nespustili podľa plánu. [@s76] [@s77]

  • Neskoršie vyšetrovanie odhalilo ďalšie problémy, ale to nás už nemusí zaujímať. Problém Starliner-u spadá do inžinierskych problémov, kde hlavnú úlohu zohral čas. A času sa budeme venovať na tejto prednáške.

Motivácia

  • (slide) Koľkí z vás máte hodinky? Ideálne - koľkí z vás nemáte chytré hodinky, proste len klasické “digitálky” alebo ručičkové hodinky? Tak mi teraz povedzte, koľko je hodín.

  • No a máme tu problém - toľkí z vás majú hodinky a aj tak mi neviete povedať, koľko je hodín. Pretože každému ukazujú čas s nejakou odchýlkou, ktorá sa v niektorých prípadoch dá rátať na sekundy a v niektorých na minúty. A potom sú niektorí, ktorí majú schválne čas posunutý o pár minút dopredu, aby všetko stihli. To všetko prispieva k tomu, že nevieme presne určiť aktuálny čas.

  • Poznať správny čas je veľmi dôležité. A to rovnako aj v svete IoT zariadení. Niekoľko príkladov, kedy sa oplatí poznať aktuálny čas:

    • ak uchovávate, resp. logujete údaje spolu s ich časovou značkou (časozberné údaje),
    • ak potrebujete spúšťať isté činnosti nie po uplynutí časového intervalu, ale presne v stanovený čas,
    • ak na zariadení potrebujete ukladať súbory s názvom, v ktorom sa nachádza časová značka,
    • a iné.
  • Preto je veľmi dôležité, aby komunikujúce zariadenia poznali nie len správny čas, ale mali všetky aj rovnaký čas nastavený. Nemôže nastať situácia, keď čas odoslania v prijatej správe je z pohľadu prijímajúceho klienta v budúcnosti.

  • Pozrieme sa teda na to, ako si aktuálny čas zapamätať a samozrejme - ako zabezpečiť synchronizáciu času medzi zariadeniami v sieti.

Hodiny reálneho času

  • (slide) Real-Time Clock (RTC) alebo hodiny reálneho času sú počítačové hodiny, ktoré sledujú aktuálny čas. Najčastejšie sú realizované vo forme samostatného integrovaného obvodu.

  • (slide) Takýto obvod sa nachádza aj na základných doskách počítačov. Spoznáte ho napr. aj podľa toho, že v jeho blízkosti sa nachádza gombíková baterka, ktorá ho zásobuje energiou aj v prípade, ak je počítač vypnutý. RTC sleduje čas stále, ale iba ak má elektrickú energiu.

  • (slide) V prípade, že chcete funkcionalitu hodín reálneho času použiť aj s niektorým mikrokontrolérom, musíte si overiť, či ho ten mikrokontrolér má alebo nie. Ak nie, môžete k nemu taký modul pripojiť. Príkladom takéhoto modulu môže byť napr. modul DS1302 alebo DS3231. Tieto moduly sa líšia prevedením, vlastnosťami ako aj spôsobom komunikácie s mikrokontrolérom. Súčasťou týchto modulov je však samozrejme aj miesto pre batériu, aby modul nezabudol aktuálny čas aj po odpojení mikrokontroléra od zdroja elektrickej energie.

    RTC Module DS3231 (zdroj)

Podpora RTC v ESP32

  • (slide) V prípade mikrokontroléra ESP32 nie je potrebné používať osobitný externý modul, pretože mikrokontrolér je takýmto modulom už vybavený. Aj napriek tomu však niektoré riešenia využívajúce tento mikrokontrolér majú osobitný RTC modul hlavne kvôli neustálemu externému napájaniu.

    Blokový diagram ESP32 (zdroj)
  • Podpora pre hodiny reálneho času sa nachádza priamo v jazyku MicroPython - v module machine sa priamo nachádza trieda RTC. Takže ak chceme začať s modulom pracovať, tak importneme uvedenú triedu a vytvoríme objekt z triedy RTC:

    >>> from machine import RTC
    >>> rtc = RTC()

Získanie aktuálneho dátumu a času

  • Aktuálny dátum a čas získame volaním metódy .datetime():

    >>> rtc.datetime()
    (2000, 1, 1, 5, 0, 2, 32, 184)
  • Výsledkom volania bude n-tica, ktorá obsahuje 8 prvkov. Ich význam je nasledovný (zľava doprava):

    • year - rok
    • month - mesiac
    • day - deň
    • weekday - deň v týždni, pričom hodnota 0 pripadá na pondelok
    • hours - hodiny
    • minutes - minúty
    • seconds - sekundy
    • subseconds - subsekundy, čiastkové sekundy

Manuálne nastavenie dátumu a času

  • Nastaviť aktuálny čas je možné manuálne zavolaním rovnakej metódy .datetime() s parametrom n-tice obsahujúcej aktuálny dátum a čas v tvare (year, month, day, weekday, hours, minutes, seconds, subseconds):

    >>> rtc.datetime((2020, 3, 13, 4, 22, 0, 0, 0))
    >>> rtc.datetime()
    (2020, 3, 13, 4, 22, 0, 3, 964)

Udržanie času po reštartovaní

  • Ak náhodou mikrokontrolér reštartnete, informácia o aktuálnom čase sa nestratí, pretože si ho modul hodín reálneho času bude pamätať:

    >>> machine.reset()
    ...
    >>> rtc = machine.RTC()
    >>> rtc.datetime()
    (2020, 3, 13, 4, 22, 2, 36, 700)
  • Ak však mikrokontrolér odpojíme od zdroja elektrickej energie (napr. vypojíme USB kábel), tak sa modul hodín reálneho času vynuluje:

    >>> rtc = machine.RTC()
    >>> rtc.datetime()
    (2000, 1, 1, 5, 0, 0, 13, 980)

Počiatok epochy

  • (slide) Dátum a čas, ktorý je na mikrokontroléri nastavený po jeho odpojení a opätovnom pripojení, je 1.1.2000 00:00:00. Tento čas je častokrát na mikrokontroléroch používaný ako počiatok epochy (z angl. time epoch alebo len epoch). Štandardne sa však na bežných stolových počítačoch používa ako počiatok dátum 1.1.1970 00:00:00 známy tiež ako Unixový čas.

  • Epocha reprezentuje moment v čase, od ktorého počítače merajú čas. Je to v podstate referečný bod, voči ktorému ho meráme. Čas, ktorý používame v bežnom živote, sme začali merať v roku 0. Míľnikom alebo udalosťou, s ktoru si tento míľnik spájame, je narodenie Ježiša Krista. Preto zvykneme v niektorých prípadoch dopĺňať časový údaj aj s doplnkom pred Kristom alebo po Kristovi, prípadne pred naším letopočtom alebo nášho letopočtu.

  • Občas však nepotrebujeme merať čas od počiatku epochy, ale napr. potrebujeme odmerať čas behu šprintéra na 100m. Vtedy je referenčným bodom moment, kedy sa spustia stopky. Výsledný čas behu následne zistíme ako rozdiel času, kedy šprintér dobehol od času, kedy sme stopky spustili. Našťastie sa však stopky spúšťajú z hodnoty 0, takže výsledný nameraný čas rovno predstavuje čas, za ktorý šprintér prebehol určenú vzdialenosť.

  • Takýto referenčný bod samozrejme nepoužívame len v prípade merania času. Rovnako tak ho používame aj pri iných meraniach, ako napr. pri meraní výšky. Aj tu potrebujeme mať referenčný bod, voči ktorému výšku budeme merať. A tá môže byť napr. samotná zem, ak meriame napr. výšku človeka alebo budovy, ale rovnako tak môže byť aj hladina mora, ak meriame nadmorskú výšku.

  • Samotný čas je následne reprezentovaný celým číslom so znamienkom ako počet sekúnd, ktoré uplynuli od počiatku epochy. Kladná hodnota hovorí, koľko sekúnd uplynulo od počiatku epochy a záporná hodnota zasa hovorí o tom, koľko sekúnd uplynulo pred počiatkom epochy. Takto môžeme od počiatku epochy chodiť ako do budúcnosti tak aj do minulosti.

Rozličné počiatky epochy v systémoch

  • (slide) Samozrejme v rozličných aplikáciách a systémoch máme rozličné počiatky epochy. Napríklad [@wikipediaEpoch]:

    • GPS systémy používajú ako počiatok epochy dátum 6.jan.1980
    • spomínaný počiatok epochy 1.jan.2000 okrem mikrokontrolérov používajú napr. aj PostgreSQL alebo ZigBee UTCTime
    • MS Excel alebo IBM Lotus Notes 1, 2, 3 používajú dátum 0.jan.1900
    • systém MATLAB používa dátum 0.jan.1 pred n.l.

Práca s časom v jazyku MicroPython

  • (slide) Na prácu s časom a dátumom v jazyku MicroPython máme k dispozícii modul utime. Tento modul je mikro implementáciou modulu time zo štandardnej knižnice jazyka Python, ktorý má rovnakú funkcionalitu. Ak teda poznáte modul time zo štandardnej knižnice jazyka, práca s modulom utime bude pre vás úplne prirodzená.

  • Modul utime poskytuje funkcie pre získanie aktuálneho času a dútumu, pre meranie časových intervalov a taktiež funkcie pre pozastavenie kódu.

Zistenie počiatku epochy v jazyku MicroPython

  • (slide) Ak chcete zisiť, aký počiatok epochy používa váš systém alebo zariadenie, môžete tak urobiť zavolaním funkcie gmtime() z modulu utime s parametrom 0:

    >>> import utime
    >>> utime.gmtime(0)
    (2000, 1, 1, 0, 0, 0, 5, 1)
  • Výsledkom volania je 8-ica, kde význam jednotlivých prvkov je nasledovný (zľava doprava):

    • year - rok
    • month - mesiac (1 - 12)
    • mday - deň v mesiaci (1 - 31)
    • hour - hodina (0 - 23)
    • minute - minúta (0 - 59)
    • second - sekunda (0 - 59)
    • weekday - deň v týždni (0 - 6, pričom hodnota 0 pripadá na pondelok)
    • yearday - deň v roku (1 - 366)
  • To, že 1. január 2000 naozaj pripadá na sobotu, si môžeme overiť napríklad príkazom cal v príkazovom riadku OS Linux:

    $ cal 1 1 2000
        január 2000
    Po Ut St Št Pi So Ne
                    1  2
    3  4  5  6  7  8  9
    10 11 12 13 14 15 16
    17 18 19 20 21 22 23
    24 25 26 27 28 29 30
    31

Zistenie počtu sekúnd od počiatku epochy

  • (slide) Ak chceme na mikrokontroléri získať aktuálny čas v počte sekúnd od počiatku epochy, zavoláme funkciu time(), ktorá sa nachádzame v module utime:

    >>> import utime
    >>> utime.time()
    669375512

Konverzia na štruktúru reprezentujúcu čas

  • Spätne konvertovať čas z počtu sekúnd od počiatku epochy na 8 prvkovú nticu je možné pomocou funkcie gmtime():

    >>> import utime
    >>> secs = utime.time()
    >>> utime.gmtime(secs)
    (2021, 3, 18, 9, 46, 33, 3, 77)

Problém roku 2038

  • V mnohých systémoch sa na reprezentáciu času používa štandardný znamienkový typ int, ktorý v pamäti zaberá 32b, resp 4B. Jeho maximálnu hodnotu vieme vypočítať ako:

    \[\frac{2^{32}}{2} + 1 = 2147483647\]

  • Ak chceme zistiť, na ktorý dátum tento počet pripadá, môžeme v jazyku Python napísať:

    >>> import time
    >>> time.gmtime(2147483647)
    time.struct_time(tm_year=2038, tm_mon=1, tm_mday=19, tm_hour=3, tm_min=14,
                     tm_sec=7, tm_wday=1, tm_yday=19, tm_isdst=0)
  • Posledný čas, ktorý je možné na 4B zobraziť, je teda 19.jan.2038 o 03:14:07. O jednu sekundu neskôr dôjde k problému, ktorý poznáme pod názvom pretečenie celého čísla (z angl. integer overflow).

  • Nás však bude zaujímať, ako je to na mikrokontroléri ESP32 v jazyku MicroPython. Tu samozrejme netreba zabudnúť, že tento problém nastane o 30 rokov neskôr, pretože počiatok epochy je o 30 rokov posunutý. To, na aký dátum tento termín pripadá, môžeme zistiť podobne, ako v jazyku Python:

    >>> import utime
    >>> utime.gmtime(2147483647)
    (2068, 1, 19, 3, 14, 7, 3, 19)
  • Takže k pretečeniu v tomto prípade dôjde 19.jan.2068 o 03:14:07. To, ako sa systém bude tváriť a či k tomuto pretečeniu dôjde, môžeme vyskúšať pomocou nasledujúceho kódu. Vypisovať v ňom budeme dve informácie:

    • reprezentáciu aktuálneho času z modulu reálneho času (trieda RTC), a
    • počet uplynutých sekúnd v podobe celého čísla.
    import utime
    from machine import RTC
    
    rtc = RTC()
    rtc.datetime((2068, 1, 19, 0, 3, 14, 0, 0))
    
    while True:
        print(rtc.datetime(), utime.time())
        utime.sleep(1)
  • Po spustení uvidíme, že k pretečeniu naozaj dôjde, ale objekt hodín reálneho času tento problém zvládne:

    (2068, 1, 19, 3, 3, 14, 6, 2301) 2147483646
    (2068, 1, 19, 3, 3, 14, 7, 2550) 2147483647
    (2068, 1, 19, 3, 3, 14, 8, 2799) -2147483648
    (2068, 1, 19, 3, 3, 14, 9, 3049) -2147483647

Network Time Protocol

  • Pri práci s časom však môže stále dôjsť ešte k dvom problém. Tým prvým je, že hodiny sa zvyknú časom rozsynchronizovať a čím dlhšie nebudú opätovne zosynchronizované, tým bude odchýlka od reálneho času väčšia.

  • Tým druhým problémom je, že hodiny potrebujeme nastaviť manuálne zakaždým, keď dôjde k výmene batérie. To však nie je veľmi praktické, nakoľko je potrebné vykonať ručný zásah do kódu, kde nastavíme čas a dátum podľa aktuálneho času. A pri manuálnom nastavovaní času existuje veľmi vysoká pravdepodobnosť toho, že čas, ktorý nastavíme na zariadení ručne, bude oproti skutočnému času nepresný.

  • (slide) Pokiaľ je však zariadenie pripojené do internetu, je možné za týmto účelom použiť Network Time Protocol (NTP). Network Time Protocol je sieťový protokol pre synchronizáciu času v zariadeniach pripojených do siete. Protokol NTP bol vytvorený už pred rokom 1985, vďaka čomu je jedným z najstarších v súčasnosti stále používaných protokolov.

Architektúra NTP

  • (slide) Aby protokol NTP pracoval, niekto musí poznať správny čas. Ak by však všetci klienti pristupovali len k jednému zdroju presného času, odozva by trvala veľmi dlho. Miesto toho NTP protokol používa hierarchickú sieť zariadení.

    NTP Servers and Clients [@wikipediaNTP]
  • Každá vrstva v tejto stieti sa nazýva stratum. Na najvyššej vrstve, tzv. stratum 0 sa nachádza zdroj reálneho času, čo môžu byť napr. atómové hodiny, GPS a iné. Tieto hodiny sú pripojené k zariadeniam na vrstve stratum 1 priamo, napr. cez rozhranie USB. Zariadenia na vrstve stratum 0 sa tiež označujú ako referenčné hodiny (z angl. reference clocks), resp. referenčný čas.

  • Čas sa dá následne získavať až z vrstvy stratum 1. Zariadenia na tejto vrstve sú tiež označované ako primárne časové servery (z angl. primary time servers). Z pohľadu získania času budú mať tieto zariadenia najnižšiu odchýlku oproti reálnemu času.

  • Zisťovať čas zo zariadení na vrstve stratum 1 však nie je odporúčaný spôsob. Opäť by hrozilo, že zariadenie bude zahltené požiadavkami a nebude ich stíhať všetky obsluhovať. Preto je odporúčané čas na klientskych zariadeniach získavať až z vrstiev stratum 2 a vyšších.

  • Tu je však jeden problém - čím je úroveň vrstvy stratum vyššia, tým väčšia bude aj časová odchýlka od zdroja reálneho času. Aby bola táto odchýlka čo najmenšia, dokážu sa jednotlivé zariadenia synchronizovať na základe údajov z viacerých zariadení. A to nie len vertikálne (smerom k nižším vrstvám stratum), ale aj horizontálne.

Podpora protokolu NTP v počítačoch

  • (slide) Podpora protokolu NTP sa nachádza aj v bežných operačných systémoch. V linuxových operačných systémoch si dokonca môžete vybrať aj z viacerých démonov, ktorí sa starajú o synchronizáciu času.

  • Aktuálne sa vo veľkých linuxových distribúciách používa chrony. Klient z príkazového riadku sa volá chronyc a vypísať aktuálne informácie o hodinách môžete pomocou príkazu tracking:

    $ chronyc tracking
    Reference ID    : 2E1D02AB (ns0.govps.gr)
    Stratum         : 3
    Ref time (UTC)  : Tue Mar 24 19:05:29 2020
    System time     : 0.001544221 seconds fast of NTP time
    Last offset     : +0.000488482 seconds
    RMS offset      : 0.004124337 seconds
    Frequency       : 9.526 ppm fast
    Residual freq   : +0.001 ppm
    Skew            : 0.168 ppm
    Root delay      : 0.034044463 seconds
    Root dispersion : 0.021502025 seconds
    Update interval : 1041.6 seconds
    Leap status     : Normal
  • Z tohto výstupu nás môže zaujímať niekoľko hodnôt:

    • Reference ID - Toto je referencia počítača, prípadne aj s IP adresou alebo doménovým záznamom, voči ktorému sa náš klient synchronizoval.

    • Stratum - Toto číslo hovorí o tom, na ktorej vrstve stratum sa nachádza server, voči ktorému prebehla synchronizácia. Poprípade toto číslo hovorí o tom, ako ďaleko sa tento server nachádza od počítača, ku ktorému sú pripojené hodiny reálneho času. Túto vzdialenosť vieme vypočítať ako stratum -1. V uvedenom prípade je teda server vzdialený od počítača s pripojenými hodinami reálneho času na 2 hop-y.

    • Ref Time - Čas (UTC), kedy došlo k poslednej synchronizácii oproti referenčnému zdroju.

    • System time - Za normálnych okolností chrony nikdy nemení čas priamo, pretože skok v čase môže mať rozličné následky v rozličných aplikáciách. Miesto toho sa dorovnanie odchýlky vyrieši spomalením alebo zrýchlením hodín, pokiaľ nie je táto odchýlka odstránená. Potom hodiny opäť pôjdu normálnou rýchlosťou. Hodnota na tomto riadku vyjadruje opísanú odchýlku.

    • Update interval - Časový interval medzi dvoma poslednými aktualizáciami času.

  • (slide) Pri konfigurovaní služby je potrebné zadať adresu zariadenia, voči ktorému sa chcete synchronizovať. Za tým účelom existuje stránka www.ntppool.org/, kde nájdete konfiguráciu v podobe zoznamu adries zariadení, voči ktorým sa bude to vaše synchronizovať. Obecne stačí zadať adresu pool.ntp.org, ale rovnako je možné si vybrať zoznam serverov pre konkrétnu krajinu.

Podpora protokolu NTP v jazyku Micropython

  • (slide) Na zariadeniach s jazykom Micropython môžeme pre synchronizáciu času cez protokol NTP použiť modul ntptime. Jeho funkcie sa automaticky postarajú aj o nastavenie aktuálneho času zariadenia priamo po synchronizácii času.

  • Ak chceme modul ntptime začať používať, je potrebné ho najprv importovať:

    >>> import ntptime
  • Tento modul obsahuje niekoľko metód a vlastností. Ich kompletný zoznam si môžeme vypísať napríklad zavolaním:

    >>> dir(ntptime)
    ['__class__', '__name__', '__file__', 'socket', 'struct', 'time',
     'NTP_DELTA', 'host', 'settime']
  • Ak si napr. necháme zobraziť obsah premennej .host, uvidíme adresu zariadenia, voči ktorému sa bude náš mikrokontrolér synchronizovať:

    >>> ntptime.host
    'pool.ntp.org'
  • Samotnú synchronizáciu času zabezpečíme volaním funkcie settime() z tohto modulu:

    >>> ntptime.settime()
  • Čas následne overíme zavolaním metódy .datetime() nad inštanciou triedy RTC:

    >>> rtc = machine.RTC()
    >>> rtc.datetime()
    (2020, 3, 14, 5, 13, 4, 11, 807)

Koordinovaný svetový čas

  • Zavolaním funkcie settime() nad modulom ntptime dôjde k nastaveniu aktuálneho času na mikrokontroléri pomocou protokolu NTP. Ak sa však pozrieme na čas, ktorý bol nastavený a porovnáme ho s aktuálnym časom, uvidíme hodinový alebo dvojhodinový rozdiel podľa toho, v ktorom mesiaci to volanie vykonávame. Lokálny čas teda bude mať o hodinu/dve viac, ako čas získaný z NTP servera. Ako je to možné?

  • (slide) Čas, ktorý funkcia settime() vrátila, je totiž koordinovaný svetový čas známy pod skratkou UTC (z anlg. Coordinated Universal Time). Jedná sa o časový štandard založený na Medzinárodnom atómovom čase s priestupnou sekundou. Tá sa aplikuje nepravidelne buď pridaním (alebo teoreticky odobratím) sekundy, aby sa dosiahla synchronizácia so spomaľujúcou sa rotáciou planéty Zem. Deň, kedy dôjde k pripočítaniu alebo odpočítaniu priestupnej sekundy nekončí štandardne v čase 23:59:59, ale 23:59:60, resp. 23:59:58. Obyčajne sa jedná o 30. jún alebo 31. december v závislosti od toho, ktorý deň nastane skôr. [@wikipediaUTC]

  • Systém UTC je nástupcom GMT (z angl. Greenwich Mean Time – greenwichský stredný čas) a v neformálnom vyjadrovaní je s ním niekedy zamieňaný. Systém GMT sa totiž odvíja len od rotácie Zeme, takže je nezávislý od prestupných sekúnd.

  • (slide) Koordinovaný svetový čas sa používa v okolí Nultého poludníka, resp. Greenwitchského poludníka (prime meridian, Greenwitch meridian). Tento poludník rozdeľuje Zem na západnú a východnú hemisféru, resp. pologuľu.

    Nultý poludník
  • (slide) Greenwitchský poludník prechádza priamo cez Kráľovskú hvezdáreň (z angl. Royal Observatory) v Greenwitch-i v Londýne. A keďže sa jedná o “atrakciu”, poludník naozaj fyzicky prechádza cez túto oblasť, takže si môžete spraviť fotku, ako stojíte jednou nohou na východnej a jednou na západnej hemisfére.

Časové pásmo

  • To ale stále nevysvetľuje, prečo čas, ktorý sme dostali z NTP servera, je o hodinu posunutý oproti nášmu lokálnemu času. Tento posun je spôsobený tým, že čas, ktorý sme dostali z NTP servera, sa nachádza v inom časovom pásme, ako sa nachádzame my.

  • Systém časových pásiem sa postupne vytváral na prelome 19. a 20 storočia. Zrejme najviac úsilia do tejto oblasti investoval Kanaďan narodený v Škótsku s menom Sir Sandford Fleming. Svoj návrh o rozdelení sveta na časové pásma obhajoval na niekoľkých konferenciách. Trvalo však mnoho rokov, kým sa časové pásma naozaj aplikovali a začali používať.

Mapa časových pásiem

Rozdelenie sveta do časových pásiem

  • Základné vlastnosti fungovania časových pásiem sú nasledovné:

    • Celý svet je rozdelený do 24 časových pásiem. Keďže planéta Zem sa otáča okolo vlastnej osi, za 24 hodín sa otočí o 360°. To znamená, že za hodinu sa otočí o 15° zemepisnej dĺžky. Toto číslo vyjadruje aj šírku jednej časovej zóny.

      \[\frac{360°}{24} = 15°\]

    • Dve susedné časové pásma sa odlišujú o 1 hodinu.

    • (slide) Stred každého časového pásma je reprezentovaný každých 15° zemepisnej dĺžky. Takže napríklad časové pásmo okolo Nultého poludníka sa rozkladá od 7.5° západnej dĺžky po 7.5° východnej dĺžky.

      Šírka jedného časového pásma
    • Smerom na východ od Nultého poludníka čas získavame. To znamená, že pri prechode každým časovým pásmom smerom na východ pripočítame jednu hodinu. Smerom na západ od Nultého poludníka čas naopak strácame, takže pri prechode každým časovým pásmom hodinu odpočítavame.

      Za toto správanie je zodpovedné Slnko, ktoré výchádza na východe. Takže krajiny, ktoré sa nachádzajú na východnej pologuli, začali deň omnoho skôr ako tie, ktoré sa nachádzajú na západnej pologuli.

    • Poludník na 180° západnej alebo východnej dĺžky sa volá dátumová hranica (z angl. International Date Line). V prípade, že dátumovú hranicu prekročíte smerom na západ, musíte pripočítať 1 deň. V prípade, že dátumovú hranicu prekročíte smerom na východ, musíte jeden deň odpočítať.

  • (slide) Za zmienku stojí aj to, že niektoré časové pásma sú pomenované, ako napríklad:

    • CET - Central European Time, UTC+01:00
    • PST - Pacific Standard Time, UTC-08:00
    • MSK - Moscow Standard Time, UTC+03:00

Výnimky v organizácii časových pásiem

  • (slide) Aj keď systém časových pásiem je navrhnutý veľmi logicky, sú krajiny, ktoré používajú výnimky. Napríklad Čína používa jedno časové pásmo pre celú krajinu, ktorá prechádza cez 4 časové pásma.

  • Niektoré krajiny zasa nepoužívajú hodinové odchýlky, ale 30 a 45 minútové. To je prípad aj kanadského ostrovu Newfoundland, ktorý používa časový posun UTC-03:30, alebo Nepálu, ktorý používa 45 minútový posun - UTC+05:45.

  • (slide) Problémy týkajúce sa časových pásiem a rozličné jeho výnimky vtipne zhrnul Tom Scott v jednom zo svojich videí na YouTube kanáli Compouterphile s názvom The Problem with Time & Timezones [@youtubeTheProblemWithTimeAndTimezones]. Ak vás táto problematika zaujíma, určite si ho pozrite.

Podpora pre časové pásma v jazyk MicroPython pre ESP32

  • (slide) Jazyk MicroPython nemá podporu pre časové zóny. To je spôsobené najmä tým, že databáza časových zón, známa tiež pod skratkou tzdata alebo tz databáza (viď [@wikipediaTzdata]) zaberá po rozbalení na disku niekoľko MB, čo obyčajne prevyšuje veľkosť flash pamäte mikrokontroléra.

  • Ak však budete chieť pracovať s časovými zónami na mikrokontroléri, musíte si prepočet na lokálny čas urobiť sami. Odchýlku od UTC si môžete uložiť napr. niekde do konfiguračného súboru alebo priamo do súboru boot.py a v prípade potreby ju použite.

  • Odporúčaným spôsobom je však používať pre všetky časy a časové značky vo vašej aplikácii priamo čas UTC. Prepočet na lokálny čas následne vykonáte až na strane klientskej aplikácie.

  • Používať priamo čas UTC je veľmi praktické. Nemusíte sa potom starať o potrebnú konfiguráciu navyše, rovnako tak o žiadne prepočty a odchýlky a nemusíte tiež dávať pozor na dátum prechodu na zimný alebo na letný čas. Plne sa môžete sústrediť na vývoj vašej aplikácie a jej funkcionality.

ISO 8601

  • Pre reprezentáciu dátumu a času v textovej forme máme k dispozícii ISO štandard 8601. Jeho výhodou je, že súčasťou textovej informácie je aj informácia ohľadom časového pásma. Použitie tohto ISO štandardu odstraňuje nezrovnalosti spojené s rozličnými formátmi a následným prevodom z textovej formy do vhodnej reprezentácie.

    XKCD: ISO 8601
  • Štandard samozrejme definuje rozličné reprezentácie časových informácií, ako je napr. samostatný čas a samostatný dátum. Nás však bude zaujímať, ako reprezentovať kompletnú informáciu ohľadom aktuálneho času a dátumu. To si ukážeme na nasledujúcich dvoch príkladoch.

  • (slide) V prípade, že čas reprezentuje priamo UTC, za časovú zložku sa zapisuje písmeno Z. Toto písmeno reprezentuje nulový posun (zero). Príklad môže byť 2022-03-20T12:34:56Z. Čas UTC je tiež známy ako “Zulu” čas, pretože slovo “Zulu” sa používa v hláskovacej tabuľke Mezinárodnej organizácie pre civilné letectvo ICAO pre písmeno Z.

  • (slide) V prípade, ak potrebujeme uviesť, že tento čas platí pre naše časové pásmo s posunom jednej hodiny (označené ako Europe/Bratislava alebo CET), čas bude reprezentovaný ako 2022-03-20T12:34:56+01:00.

Kedy synchronizovať čas?

  • Podobne ako v prípade bežných hodiniek, aj tu dochádza k rozsynchronizovaniu času. Ak teda čas zosynchronizujete pri štarte zariadenia a jeho následnom pripojení do siete, nemusí to znamenať, že rovnakú odchýlku bude mať aj o týždeň po nepretržitej prevádzke. Je preto dobré plánovať ďalšiu synchronizáciu.

  • Linuxové systémy tento problém riešia tak, že k časovej synchronizácii dôjde zakaždým, keď dochádza k pripojeniu do internetu. To je dôležité napr. pri mobilných zariadeniach, ako sú napr. laptopy. Podobne teda môžu fungovať aj IoT zariadenia, keďže aj tie nepotrebujú sieťovú konektivitu neustále, ale len v (ne)pravidelných intervaloch. Samotná synchronizácia netrvá dlho, čo čas potrebný pre zotrvanie v sieti predĺži max. o niekoľko sekúnd.

Záver

  • V rámci tejto témy sme sa venovali času, pretože čas je nesmierne dôležitý. To, aký je dôležitý, ilustrovala prvá misia kozmickej lode Starliner, ktorá dopadla neúspešne len vďaka tomu, že niekto nenastavil správne hodiny.

  • Problematika času je veľmi dôležitá, ale rovnako aj veľmi komplexná. Poznať aktuálny čas znamená mať miesto, kde je uložený. Poznať správny čas znamená mať autoritu, ktorej dôverujete, že vám hodnotu správneho času povie. A aj keď odpoveď dostanete, ešte to nemusí znamenať, že ste dostali aj informáciu týkajúcu sa vášho miestneho času.

  • A nakoniec - netreba zabúdať ani na to, ako čas zobrazíte koncovému používateľovi, pretože napríklad formátovanie dátumu môže byť v rozličných krajinách rôzne. A tak sa jednoducho môže stať, že ak rovnaký dátum zobrazíte v dvoch rozličných krajinách, tak môže pripadať na dva rozličné termíny.

  • Hlavné odporúčanie preto znie - pre svoju internú reprezentáciu používajte vždy čas UTC a formátovanie nechajte až na klientske aplikácie.

  • No a nezabudnite, že čas sú peniaze. A ak si tým náhodou nebudete istí, tak si spomeňte, ako dopadol Starliner ;)