Obsah / Utility / CALENDAR / Výpočet rozšířených položek kalendáře
Zdrojový kód: INCLUDE\UTIL\CALENDAR.INC, UTIL\CALENDAR.ASM
Výpočet rozšířených položek kalendáře
|
Funkce DateTimeExt vygeneruje rozšířené položky struktury DATETIME - tj. den v roce, číslo týdne, příznaky - včetně dne v týdnu. Vstupními daty funkce jsou položky data (den, měsíc, rok) ve struktuře DATETIME, na kterou ukazuje ukazatel v registru EBX. Datum by mělo být platné (funkce neřeší přetékání položek do vyšších řádů), jinak bude výsledek nedefinovaný.
|
Po úschově registrů je to registru ESI připraven ukazatel na strukturu DATETIME (ukazatel zůstává platný po celou dobu funkce) a jsou vynulovány příznaky ve struktuře DATETIME. Ze struktury DATETIME je načteno datum a uloženo do registrů AL (den), DL (měsíc) a CX (rok).
|
S využitím funkce CheckLeapYear je připraven příznak přestupnosti roku. Funkce CheckLeapYear testuje rok v registru CX a pokud je přestupný, navrátí nastavený příznak CY. Příznakem ve struktuře DATETIME je bit 0, proto může být nastaven instrukcí ADC.
|
Datum v registrech AL, DL a CX je překonvertováno funkcí DateToAbsDay na absolutní den od 1. ledna roku 1 n.l. (navráceno v registru EAX).
|
Porovnáním absolutního dne se SPLITDATE, což je datum 15. října 1582, kdy začal platit Gregoriánský kalendář, je rozlišen Juliánský a Gregoriánský kalendář a nastaven příslušný bit v příznacích.
|
Číslo dne v týdnu se zjistí podobně jako ve funkci AbsToDateTime. Do registru EDI se připraví číslo absolutního dne s přičtenou korekcí 4 dnů. Toto číslo se bude dělit číslem 7, ale namísto dělení se použije rychlejší operace násobení převrácenou hodnotou čísla, tedy číslem 100000000h/7 (zaokrouhleno nahoru). V registru EDX bude po násobení absolutní číslo týdne. Vynásobením zpět číslem 7 a odečtením od původního počtu dnů zůstane v registru EAX číslo dne v týdnu, který se uloží do struktury DATETIME.
|
Pomocí funkce DateToAbsDay se zjistí absolutní číslo prvního dne v roce, tj. datum se stejným rokem, ale den a měsíc mají číslo 1. Odečtením absolutního čísla současného dne od prvního dne v roce se obdrží číslo dne v roce a to se uloží do struktury DATETIME.
|
Při výpočtu čísla týdne potřebujeme znát den v týdnu, který připadá na datum 4. ledna. Podle definice ISO-8601 je prvním týdnem roku týden obsahující 4. leden (týden obsahující první čtvrtek roku). Při výpočtu dne v týdnu připadajícího na 4. ledna se využije den v týdnu aktuálního dne a číslo aktuálního dne v roce. Po odečtení čísla aktuálního dne ode dne v týdnu aktuálního dne se získá den v týdnu prvního dne v roce (neopravený operací modulo). Přičtením 2 se obdrží neopravený den v týdnu pro 4. ledna. Přičtením 53*7 se údaj posune do oblasti kladných hodnot. Vynásobením převrácenou hodnotou 7, zpětným přepočtem na dny a odečtením od původní hodnoty se obdrží číslo dne v týdnu pro 4. ledna (registr EBX) s počátkem v 0 (tj. 0=pondělí, ... 6=neděle).
|
Dále je zapotřebí znát počet týdnů v roce, abychom mohli rozpoznat přetečení konce roku do prvního týdne následujícího roku. K tomu poslouží následující tabulky představující možné varianty začátků roku.
Nepřestupný rok:
Začátek roku | Offset
1. týdne od začátku roku |
1.1. je v prvním týdnu roku |
Délka
roku (365 dnů) |
Konec roku | 31.12.
je v posledním týdnu roku |
Počet týdnů | ||||||||||||
Po | Út | St | Čt | Pá | So | Ne | Po | Út | St | Čt | Pá | So | Ne | |||||
1. | 1 | ne | 1 + 51*7 + 7 | 25. | 26. | 27. | 28. | 29. | 30. | 31. | ano | 52 | ||||||
1. | 2. | 2 | ne | 2 + 51*7 + 6 | 26. | 27. | 28. | 29. | 30. | 31. | 1. | ano | 52 | |||||
1. | 2. | 3. | 3 | ne | 3 + 51*7 + 5 | 27. | 28. | 29. | 30. | 31. | 1. | 2. | ano | 52 | ||||
1. | 2. | 3. | 4. | -3 | ano | 4 + 51*7 + 4 | 28. | 29. | 30. | 31. | 1. | 2. | 3. | ano | 53 | |||
1. | 2. | 3. | 4. | 5. | -2 | ano | 5 + 51*7 + 3 | 29. | 30. | 31. | 1. | 2. | 3. | 4. | ne | 52 | ||
1. | 2. | 3. | 4. | 5. | 6. | -1 | ano | 6 + 51*7 + 2 | 30. | 31. | 1. | 2. | 3. | 4. | 5. | ne | 52 | |
1. | 2. | 3. | 4. | 5. | 6. | 7. | 0 | ano | 7 + 51*7 + 1 | 31. | 1. | 2. | 3. | 4. | 5. | 6. | ne | 52 |
Přestupný rok:
Začátek roku | Offset
1. týdne od začátku roku |
1.1. je v prvním týdnu roku |
Délka
roku (366 dnů) |
Konec roku | 31.12.
je v posledním týdnu roku |
Počet týdnů | ||||||||||||
Po | Út | St | Čt | Pá | So | Ne | Po | Út | St | Čt | Pá | So | Ne | |||||
1. | 1 | ne | 1 + 52*7 + 1 | 31. | 1. | 2. | 3. | 4. | 5. | 6. | ne | 52 | ||||||
1. | 2. | 2 | ne | 2 + 51*7 + 7 | 25. | 26. | 27. | 28. | 29. | 30. | 31. | ano | 52 | |||||
1. | 2. | 3. | 3 | ne | 3 + 51*7 + 6 | 26. | 27. | 28. | 29. | 30. | 31. | 1. | ano | 52 | ||||
1. | 2. | 3. | 4. | -3 | ano | 4 + 51*7 + 5 | 27. | 28. | 29. | 30. | 31. | 1. | 2. | ano | 53 | |||
1. | 2. | 3. | 4. | 5. | -2 | ano | 5 + 51*7 + 4 | 28. | 29. | 30. | 31. | 1. | 2. | 3. | ano | 53 | ||
1. | 2. | 3. | 4. | 5. | 6. | -1 | ano | 6 + 51*7 + 3 | 29. | 30. | 31. | 1. | 2. | 3. | 4. | ne | 52 | |
1. | 2. | 3. | 4. | 5. | 6. | 7. | 0 | ano | 7 + 51*7 + 2 | 30. | 31. | 1. | 2. | 3. | 4. | 5. | ne | 52 |
Rok 1582:
Začátek roku | Offset
1. týdne od začátku roku |
1.1. je v prvním týdnu roku |
Délka
roku (355 dnů) |
Konec roku | 31.12.
je v posledním týdnu roku |
Počet týdnů | ||||||||||||
Po | Út | St | Čt | Pá | So | Ne | Po | Út | St | Čt | Pá | So | Ne | |||||
1. | 2. | 3. | 4. | 5. | 6. | 7. | 0 | ano | 7 + 49*7 + 5 | 27. | 28. | 29. | 30. | 31. | 1. | 2. | ano | 51 |
Jak je vidět z tabulek, ve většině případů má rok 52 týdnů (přednastaveno do registru BH). Je-li 4.1. neděle, má rok vždy 53 týdnů. Ostatní dny, kromě soboty, mají vždy 52 týdnů. V případě soboty má rok 53 týdnů tehdy, jedná-li se o přestupný rok. Pro rok 1582 patří 32.12. do posledního týdne stejného roku, není proto potřeba připravovat skutečný počet týdnů.
|
Do registru EAX se připraví offset prvního týdne roku od začátku roku s využitím dne v týdnu 4. ledna (jak je vidět z tabulek).
|
Do registru EDX se připraví číslo dne v roce. Odečtením offsetu prvního týdne v roku se získá offset tohoto dne od začátku prvního týdne v roku. Přičtením čísla 7 se offset posune do kladných hodnot a zajistí se, že první týden v roce bude mít číslo 1. Vydělením číslem 7 se vypočte číslo týdne. Namísto operace dělení se použije rychlejší operace násobení převrácenou hodnotou čísla, tedy 100000000h/7 (zaokrouhleno nahoru). Číslo týdne bude v registru EDX.
|
Má-li týden číslo nula, jedná se o poslední týden předešlého roku. To se týká 1. až 3. ledna v případech, kdy 4. leden připadá na pondělí, úterý nebo středu (ve výše uvedených tabulkách se jedná o první 3 řádky). Nastaví se příznak posledního týdne předešlého roku a dále bude nutné zjistit číslo posledního týdne předešlého roku.
|
Do registru CX se připraví číslo aktuálního roku a rozliší se speciální případ roku 1583, kdy předešlý rok 1582 končí týdnem 51.
|
Připadne-li 4. leden na pondělí, bude mít předešlý rok vždy 53 týdnů. Připadne-li na středu, bude mít vždy 52 týdnů. Tuto závislost lze vypozorovat z předešlých tabulek podle posunu dnů na konci roku.
|
Připadne-li 4. leden na úterý, bude počet týdnů záviset na tom, zda předešlý rok je přestupným rokem nebo ne. Test přestupnosti roku se provede pomocí funkce CheckLeapYear. Není-li předešlý rok přestupný, bude předešlý rok končit 52. týdnem. Je-li rok přestupný, bude to týden 53. To lze opět vypozorovat porovnáním tabulek pro přestupný a nepřestupný rok.
|
Poslední test zkontroluje, zda je číslo týdne platné a zda se nejedná o první týden následujícího roku. Přitom se použije počet týdnů zjištěných dříve v registru BH. Pokud se jedná o první týden následujícího roku, nastaví se příslušný příznak a týden bude mít číslo 1. Na závěr se zjištěné číslo týdne uloží do struktury DATETIME a obnoví se registry ze zásobníku.
|
Funkce AbsToDateTimeExt je obdobou funkce AbsToDateTime. Liší se od ní tím, že po provedení převodu absolutního čas na datum a čas v rozloženém tvaru se provede ještě výpočet rozšířených položek struktury DATETIME.
Obsah / Utility / CALENDAR / Výpočet rozšířených položek kalendáře