Dnes 25.10 sa zmení tzv. letný na zimný čas. Nechám teraz bokom emotívne prajavy prečo áno, prečo nie a skúsim opísať tento „problém“ z pohľadu programátora.
Úvod:
Systém prepínania letný/zimný čas vznikol z potreby šetriť elektrickou energiou a vykonáva sa nasledovne. Vždy posledný marcový (brezen) a októbrový (říjen) víkend zo soboty na nedeľu sa skoro ráno posunie hodinová ručička http://sk.wikipedia.org/wiki/Letný_čas. Presnejšie v marci dopredu z 2 na 3 hodinu. V októbri naspať z 3 na 2 hodinu.
Pokiaľ tento problém za vás nerieši OS a vytvárate napríklad firmware pre malé zariadenie, tak stojíte pred problémom algoritmizácie (naprogramovania) prepínania letný – zimný čas. Na dokreslenie použijem zdrojový kód v jazyku C v ktorom používam štruktúru iRTC. Tá vypadá nasledovne:
struct iRTC
{
U08 Sec;
U08 Min;
U08 Hour;
enum WDAY WDay;
U08 Day;
enum MONTH Month;
U08 Year;
};
Problém č.1 – Kedy to nastane.
Problém by bol v celku ľahký, keby tam nebol ten víkend. Pokiaľ to chcete naprogramovať, musíte podľa dátum zistiť na aký deň v týždni pripadá http://sk.wikipedia.org/wiki/Algoritmus_na_výpočet_dňa_v_týždni. A tak váš FW posledných 7 dní v marci a októbri o 2 (3) hodine ráno kontroluje či náhodou nieje nedeľa. Program v C bude vypadať takto.
// urcim den v tyzdni
iRTC.WDay = GetWDay(iRTC);
// letny v marci
if(( iRTC.Month == 3 ) && ( iRTC.Day >= 25 )
&& ( iRTC.WDay == 7 ) && ( iRTC.Hour >= 2 ))
iRTC.Hour++;// posuniem hodinu pred
// zimny (normálny) v oktobri
if(( iRTC.Month == 10) && ( iRTC.Day >= 25 )
&& ( iRTC.WDay == 7 ) && ( iRTC.Hour >= 3 ))
iRTC.Hour--;// posuniem hodinu spat
Problém č.2 – Už sa tak stalo?
Pozorný čitatelia, prípadne skúsenejší programátori určite prišli na jednu chybu. Tou chybou je práve október. Máme postavenú podmienku, že ak je to posledná nedeľa v mesiaci október a sú 3 hodiny ráno tak potom posuň hodiny dozadu. No áno. Ale tie hodiny pobežia a za hodinu bude zase 3 hodín ráno. Algoritmus by teda posunul hodiny zase spať a tak stále dokola. Do podmienky teda musíme pridať že sa tak už stalo, a že už zimný čas je a nieje nutné znova prepínať. Tak zase krátky zdroják.
// letny uz v marci
if(( iRTC.Month == 3 ) && ( iRTC.Day >= 25 )
&& ( iRTC.WDay == 7 ) && ( iRTC.Hour >= 2 )) {
IsSummer=true;
iRTC.Hour++;// posuniem hodinu pred
}
// zimny (normálny) v oktobri
if(( iRTC.Month == 10) && ( iRTC.Day >= 25 )
&& ( iRTC.WDay == 7 ) && ( iRTC.Hour >= 3 )
&& (IsSummer)) {
IsSummer=false;
iRTC.Hour--;// posuniem hodinu spat
}
Problém č.3 – Ešte stále nemáme vyhrané
Kto by si po vyriešení 2 vydýchol, naplnil by len Murphyho zákoník a zistil, že vyriešením problému sa vyrojili ďalšie. Tým prvým je odveké „kam s ním“. Riešenie sme totiž postavili na premennej IsSummer ktorá celý čas udržiava stav letný/zimný. Kde ju uložiť? Do registrov, do flash, do EEPROM? A naviac to musíte neustále udržiavať aj v tej globálnej premennej IsSummer (úplne zbytočné zabranie pamete). Pri zapínaní prístroja premenú včas a správne načítať a pod. Aby toho nebolo dosť. Tak pre istotu (programátori majú radi parametre) ešte pribudne premená UseSummer. Teda či má prístroj vobec prepínať čas. Kedže sa pohybujeme na zariadeniach kde každý Byte dobrý. Zožrali sme si 2B. Tí skusenejší to naperú do 1B.
Problém č.4 – Až teraz to príde
Máme teraz 2 dni z ktorých jeden má 25 hodín a ten ďalší 23 (prípadne naopak). Poviete si maličkosť. Ale čo ak vaše zariadenie počíta priemernú spotrebu? Prípadne vyvoláva alarm ak v neakom dni spotreba prekročila hranicu, prípadne bola pod minimom. Ak sa vám stratí hodina tak výpočty idú do kelu. Z toho sa potom ďažko dostať bez „straty kytičky“. Ak aj to vyriešite, tak vaši testeri to nerozchodia a všetko, opakujem všetko, budú testovať pre normálny deň a pre deň prepnutia času. To že ste si zaniesli do programu neakú chybu je samozrejmosť.
Záver
Z vlastných skúseností viem že implementácia zaberie v kóde tak 5–7%. To nemyslím tých pár riadkov čo som sem pastol, ale práve riešenie bodu 4. Poznám dokonca programátorov, ktorý niečo také neimplementujú. Proste po prepnutí času prestanú počítať kumulatívy a priemerné hodnoty v tom dni, prípadne ich označia za nekoretné. To som opísal problém len okruhu malých zariadení. Verím že veľké SW a hlavne databázy musia mať problémy komplikovanejšie. Z pohladu programátora je prepínanie času letný/zimný vyslovená nepríjemnosť, ktorá komplikuje algoritmy, zvačšuje kód a nedá sa zmysluplne vyriešiť.
PS: V pondelok pridám aj kód ako z dátumu vyveštiť deň v týždni. Teraz ho neviem nájsť.
Váš TrSek
Zrovna se u nás ve firmě tenhle problém řešil. Kolegové co na tom dělali si pěkně mákli. Stihli to, ale tak tak, na poslední chvíli. Po jarních útrapách, kdy řešili přechod na letní čas, si mysleli, že to bude v pohodě a ono nebylo.
Jinak co se týče vámi zmiňovaných různých průměrů či limitů, to není až zase tak problém. Pokud někde čas figuruje jako primární klíč, tak není problém ho ukládat v UTC, nebo Time+Timezone (tak se to teď dělá u nás). Například při výpočtu průměrných denních hodnot se použije skutečný počet hodin (25 na podzim či 23 na jaře) takže hodnoty budou normální (pokud zanedbáme nadšení pracantů na noční 9-ti hodinové šichtě). Co se týká součtů (a limitů u nich) tak ty by se asi přímo upravovat neměli, ale při kontrole limitů, by se rozdílný počet hodin měn vzít v potaz (na podzim x * 24 / 25 a na jaře x * 24 / 23).
Jinak taková perlička na závěr. To že se tyto problémy u nás řeší teď neznamená že se u nás vyvíjí nový systém. Ten je v provozu ve spoustě továren po celém světě a zákazníci si problémů s přechodem všimli asi po 15 letech. Aneb jak se u nás říká: Bug není bug dokud se někdo neozve, a pokud se neozve ještě jednou, tak to není důležité :-)
Letní čas je ok, ale v zeměpisné délce, ve které leží ČR, je právě ten zimní absolutní zhovadilost. Jasně, v poledne svítí slunce v max. úhlu, ale k čemu to proboha je? Lidi už dávno nevstávaj do práce na šestou, a když už, tak jenom nějaká dělnická lůza ve starejch fabrikách, kde se ještě furt buduje socialismus. Běžnej programátor jako já vstává tak v 8-9 hodin (tedy když se zrovna zadaří), pak kafíčko, a pak až něco dělat. A to už je dávno světlo.
1. Opravdu zajímavý tento problém začne být ve chvíli, kdy zjistíte, že ne všude na světě se přechod realizuje ve stejný den.
2. Obvykle se tento problém řeší vhodným návrhem datového typu. Používá datový typ, kdy čas není ovlivněn letním posunem. Tento čas slouží pro veškeré výpočty. Tento "interní" čas se pak převádí na formát zobrazovaný uživateli. Jediný problém je převod času zadaného uživatelem. Ten je pro okamžik přechodu z letního času na zimní nedeterministický.
3. Opravdu těžko řešitelným problém se jeví spíše přestupný rok. Teprve tady člověk pochopí význam funkcí pro differenci datumů, když by přeci stačilo jednoduše je odečíst.
4. A pro věděcké výpočty závislé na přesnosti měření času je problémem i tzv. "leap second". Ono ne každá minuta má 60 sekund. Narozdíl od přestupného roku tohle už řada lidí neví a podle toho to dopadá.
// z datumu zisti den v tyzdni
U08 GetWDay (struct RTC)
{
U08 mcif[12] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5}; // cifra mesiaca
U08 ycif; // cifra roku
U08 ccif; // cifra storocia
U08 weekd;
ycif = (RTC.Year + (RTC.Year / 4)) % 7;
ccif = (RTC.Year % 4 - 3) * (-2);// je vzdy 6 pre roky 20xx
weekd = (RTC.Day % 7) + mcif[ RTC.Month-1 ] + ycif + ccif;
// korekcia pre priestupny rok
if( RTC.Month < 3 )
weekd = weekd + 6;
// den v tyzdni
weekd = weekd % 7;
// nula je nedela
if( weekd == 0 )
weekd = 7;
// vysledok
return weekd;
}
[9]
Asi ano. Len taka malickost ako je aktualny datum, cas.
Vzdy pritom testujes ci je to cas letny. A ak je potom posuvas hodinu. Ak si na zaciatku dna tak posuvas den, pripadne mesiac.
Alebo ked je poziadvaka na udaje z aktualneho dna potom nad kazdym udajom robis prepocty aby si zistil ci ten cas je z toho dna.
Nakoniec nato pozries a vidis ze mas kvantum podmienok. Pricom nedokazes deterministicky urcit ako dlho to trva. Az raz ti zaberie watchdog a potom ...
PS: Ono na niekedy su na zariadenia kladene poziadavky ktore zdravy rozum neberie.
Toto je fakt vec ktora hovori za vsetko. Par vedcov zhodnotilo, ze sa takto usetri elektrina a zavedie to najviac nenavidena osoba na svete (AH). Vsetci to zacnu dodrziavat a ak sa to po par rokoch zrusi, tak sa to potom zavedie znovu. Navyse dnes to ma uplne opacny vysledok a energie sa vdaka tomuto systemu spotrebuje viac. Nehovoriac o tom, kolko problemov to narobi firmam ktore z casom pracuju. Napriek tomu, to teraz tym ludom ktory to mozu ovplyvnit vobec nevadi a ludia bojujuci proti tomu, sa mozu aj upalit a nikto nepohne ani prstom. Toto ma byt 21 storocie? Ja mam skor pocit, akoby sme sa systemom vracali do stredoveku.
Celý popisovaný problém je v tom, že špatně chápete "čas". "Čas" ve vašem pojetí (třeba 17:30) se dá použít leda tak pro běžnou komunikaci mezi lidmi, kteří si zbytek doplní podle kontextu. Ve skutečnosti ale není čas jenom to číslo, ale také časové pásmo. Takže třeba 17:30 SELČ. Když tedy začnete s časem pracovat správně (tj. vedle času pracujete také s časovou zónou), odpadnou problémy se změnou, nutnost pamatovat si extra aktuální nastavení apod. Prostě jen podle data a času určíte, která časová zóna se zrovna používá, a podle toho čas zkonvertujete.
Vo voľnom čase sa venujem staručkému Turbo Pascalu na stránke www.trsek.com. Inak programujem v C/C++, PHP, SQL.
Přečteno 28 756×
Přečteno 24 686×
Přečteno 24 091×
Přečteno 23 081×
Přečteno 22 748×