Obsah / Utility / CALENDAR / Konverze data na absolutní den
Zdrojový kód: INCLUDE\UTIL\CALENDAR.INC, UTIL\CALENDAR.ASM
Konverze data na absolutní den
|
Funkce DateToAbsDay vypočítá absolutní den pro datum zadané na vstupu funkce. Vstupními parametry funkce jsou: v registru AL číslo dne v měsíci (rozsah 1 až 31, ale může být -128 až +127, při překročení hranic se opraví číslo měsíce), v registru DL číslo měsíce (rozsah 1 až 12, ale může být -128 až +127, při překročení hranic se opraví číslo roku) a v registru CX číslo roku (v rozsahu MINYEAR až MAXYEAR po případné opravě přetečení měsíce). Funkce navrátí v registru EAX absolutní den, což je den vztažený k počátku letopočtu (tj. datum 1.1.1 n.l.). Absolutní den může mít rozsah hodnot MINDAY až MAXDAY.
Konverze se provádí podle následujícího symbolického zápisu:
|
Na začátku obsahuje proměnná "m" číslo měsíce s počátkem v nule (tj. hodnoty 0 až 11). Podle čísla měsíce se připraví v proměnné "a" příznak indikující, zda měsícem je leden až únor nebo březen až prosinec. Rok se přičtením konstanty 40000 převede na kladné číslo s počátkem dělitelným 400 a s korekcí pro měsíce lede a únor. Všechny výpočty probíhají totiž tak, jako by byl přelom roku mezi únorem a březnem. Proto se i měsíc proměnné "m" upraví na offset od měsíce března (tj. březen=0, duben=1, ... prosinec=9, leden=10, únor=11).
Celočíselnou operací (která neuchovává zbytek po dělení) "(153*m + 2)/5" se vypočte offset měsíce (počet dnů) od pomocného počátku roku (kterým je 1. březen). Přičtením dne v měsíci a přičtením násobku 365*rok se zjistí absolutní den, tedy počet dnů od března roku -40000, zatím bez korekce přechodných let.
Přičtením 1/4 čísla roku se provede korekce přechodných let pro Juliánský kalendář. Odečtením 14610307 dnů se číslo dne převede zpět na offset od počátku letopočtu.
Pro den SPLITDATE a vyšší je potřeba provést další korekce pro Gregoriánský kalendář. Odečtením 1/100 čísla roku se odečtou dny pro nepřechodná staletí, příčtením 1/400 čísla roku se přičtou dny pro přechodná 400-letí, tedy století dělitelná číslem 4. Přičtením hodnoty 302 se opraví chyba rozdílu data 10 dnů a nesprávně odečtených nepřechodných staletí do roku 1582.
|
Po úschově registrů jsou do registrů připraveny vstupní parametry funkce (EAX=měsíc, EBX=den v měsíci, ECX=rok).
|
Ke správnému provádění výpočtů je nutné číslo měsíce nejdříve normalizovat, tj. uvést do rozsahu 0 až 11 (po snížení o 1). Ve většině případů nebude normalizace nutná, proto se provádí větví ležící mimo hlavní funkci, aby při běžném rozsahu hodnot nedocházelo ke zpomalování hlavní funkce. Pokud je hodnota měsíce menší než nula, přičítá se k měsíci číslo 12 a číslo roku se snižuje o 1. Je-li měsíc naopak větší než 11, odečítá se od měsíce číslo 12 a číslo roku se zvyšuje o 1.
|
Do registru EDX se připraví příznak, že měsícem je leden nebo únor ("if (m >= 2) a = 0; else a = -1;"). Porovnáním čísla měsíce (v registru AL) sníženého o 1 s hodnotou 2 se nastaví příznak CF v případě, že měsícem je leden nebo únor (tj. měsíc-1 je 0 nebo 1). Další instrukce nastaví registr EDX na hodnotu -1 v případě měsíce leden nebo únor, pro ostatní měsíce bude obsah registru EDX nulový.
|
Rok v registru ECX se upraví na kladné číslo přičtením offsetu 40000 a příznaku měsíce ledna a února ("y = year + a + 40000;").
|
Měsíc v registru EDX se upraví na offset od měsíce března ("m = m + (12 & a) - 2;"). Maskováním příznaku měsíce ledna a února číslem 12 obdržíme číslo 12 pro měsíce leden a únor, pro ostatní měsíce nám zůstane nula.
|
Nyní přepočteme číslo měsíce na počet dnů od 1. března ("(153*m + 2)/5"). Měsíc v registru EDX vynásobíme konstantou 153 a přičteme 2. Namísto dělení číslem 5 použijeme rychlejší operaci násobení převrácenou hodnotou čísla, tj. číslem 10000h/5 (zaokrouhleno nahoru). Rotací výsledku o 16 bitů doprava obdržíme požadovaný počet dnů od 1. března.
|
Přičtením čísla dne v měsíci a přičtením 365-násobku čísla roku obdržíme absolutní číslo dne bez korekce přechodných let ("date = day + (153*m + 2)/5 + y*365;").
|
Přičtením 1/4 čísla roku (dny pro přechodné roky) a odečtením počátečního offsetu kalendáře obdržíme absolutní den vztažený k počátku letopočtu pro Juliánský kalendář ("y = y/4; date = date + y - 14610307;").
|
Testem hodnoty data rozlišíme, zda se jedná o Gregoriánský kalendář ("if (date >= SPLITDATE)"). Pokud ano, připravíme si 1/100 čísla roku, přičemž víme, že rok již máme vydělený číslem 4 ("y = y / 25;"). Namísto dělení číslem 25 použijeme rychlejší násobení převrácenou hodnotou, tj. číslem 400000h/25 (zaokrouhleno nahoru). Výsledek obdržíme v registru EDX a rotací o 22 bitů doprava získáme 1/100 čísla roku, tedy číslo století (opět s přelomem let po měsíci únoru). Odečtením čísla století, přičtením 1/4 čísla století a příčtením opravného koeficientu 302 obdržíme výsledný absolutní den Gregoriánského kalendáře.
Obsah / Utility / CALENDAR / Konverze data na absolutní den