Obsah / Utility / CALENDAR / Konverze absolutního času na datum a čas
Zdrojový kód: INCLUDE\UTIL\CALENDAR.INC, UTIL\CALENDAR.ASM
Konverze absolutního času na datum a čas
|
Funkce AbsToDateTime převede absolutní čas na datum a čas v rozloženém tvaru. Registr EBX obsahuje na vstupu funkce ukazatel na strukturu DATETIME. Registry EDX:EAX obsahují absolutní čas. Absolutní čas je násobkem 100 nanosekund od 0:00:00 hodin 1. ledna roku 1 n.l. Funkce nastaví pouze položky datum, čas a den v týdnu. Položky den v roce, číslo týdne a příznaky nejsou funkcí ovlivněny. Jsou-li potřebné i tyto doplňující informace, je možné dodatečně zavolat funkci DateTimeExt nebo namísto funkce AbsToDateTime zavolat přímo funkci AbsToDateTimeExt.
Konverze se provádí podle následujícího symbolického zápisu:
|
Na začátku se připraví proměnné pro Juliánský kalendář. Proměnná "b" obsahuje přepočet pro století, u Juliánsklého kalendáře se neuplatní a proto je vynulována. Proměnná "c" obsahuje počet dnů od 1. března roku 40000 př.n.l. Všechny výpočty probíhají tak, jako by byl přelom roku mezi únorem a březnem, tím se výpočty zjednoduší, protože přechodný den připadá vždy na konec roku.
Je-li datum SPLITDATE nebo vyšší, jedná se o Gregoriánský kalendář. Opraví se počet dnů v proměnné "c". Do proměnné "b" se připraví číslo století. Odečtením počtu dnů připadajících na celá staletí zůstane v proměnné "c" číslo dne v aktuálním století.
Do proměnné "d" se připraví číslo roku v aktuálním století. Součtem století*100 a roku ve století se připraví do proměnné "b" číslo aktuálního roku (s přičteným offsetem 40000). Odečtením dnů připadajících na celé roky od počtů dnů v proměnné "c" se vypočte číslo dne od pomocného počátku roku (tedy od 1. března). Den v roce se přepočte podle vztahu "(c*5 + 2)/153" na číslo měsíce v roce, opět s počátkem v březnu. Jedná se o celočíselné dělení, zbytek po dělení se ignoruje.
Nyní se již může zjistit číslo dne v měsíci - od čísla dne v roce v proměnné "c" se odečte počet dnů od začátku roku pro aktuální měsíc podle vztahu "(153*d + 2)/5".
Do pomocné proměnné "e" se připraví pomocný příznak indikující, zda se jedná o poslední 2 měsíce roku (vztaženo k pomocnému počátku roku v březnu, takže se tedy jedná o leden nebo únor) nebo o prvních 10 měsíců (tedy březen až prosinec). Příznak se použije ve výpočtu čísla roku - od čísla roku "b" se odečte počáteční offset 40000 (který byl potřebný na převod data do kladných čísel) a provede se doplňující oprava čísla roku příčtením korekce "e".
Číslo měsíce "d" se převede na kalendářní měsíc posunem o 3 a odečtením korekce 12 v případě posledních 2 měsíců.
|
Na začátku funkce jsou uchovány použité registry, do registru ESI je připraven ukazatel na strukturu DATETIME a odečtením minimální hodnoty času MINTIMEL a MINTIMEH je čas převeden na kladné číslo vztažené k minimálnímu povolenému času.
|
Absolutní čas je vydělením číslem 60*10000000 rozdělen na stovky nanosekund v minutě (v registru EDX) a minuty (uloženo do registrů EDI:EBX). Minuty mohou být 64-bitovým číslem, proto je dělení provedeno ve 2 krocích (vyšší a nižší dvojslovo).
|
Stovky nanosekund v minutě v registru EDX budou vydělením číslem 10000000 rozloženy na sekundy a stovky nanosekund v sekundě. Namísto operace dělení je provedena rychlejší operace násobení převrácenou hodnotou, tj. číslem 40 0000 0000 0000h/10000000 (zaokrouhleno nahoru). Po vynásobení a opravě výsledku rotací o 22 bitů doprava bude v registru EDX počet sekund, který se uloží do struktury DATETIME. Počet sekund se vynásobí číslem 10000000, tím se převede zpět na stovky nanosekund, odečtením od výchozího počtu stovek nanosekund se získá zbytek stovek nanosekund v sekundě. Po vynásobení číslem 100 se uloží číslo nanosekundy do struktury DATETIME.
|
Minuty v registrech EDI:EBX jsou vydělením číslem 24*60 rozloženy na dny (registr EAX) a minuty v jednom dni (registr EDX).
|
Minuty v jednom dni (v registru EAX) budou rozděleny na hodiny a minuty v hodině. Namísto dělení číslem 60 se použije rychlejší operace násobení převrácenou hodnotou (tj. číslem 1000000h/60, zaokrouhleno nahoru). Po vynásobení a opravě výsledku rotací o 24 bitů doprava bude počet hodin (v registru CL) uložen do struktury DATETIME. Vynásobením hodin číslem 60 a odečtením od původního počtu minut ve dni se získá počet minut v hodině, ten se též uloží do struktury DATETIME.
|
Abychom zjistili číslo dne v týdnu, připravíme si do registru EBX číslo absolutního dne s přičtenou korekcí 4 dnů. Toto číslo budeme dělit číslem 7. Namísto dělení použijeme rychlejší operaci násobení převrácenou hodnotou čísla, tedy číslem 100000000h/7 (zaokrouhleno nahoru). V registru EDX obdržíme absolutní číslo týdne. Vynásobením zpět číslem 7 a odečtením od původního počtu dnů obdržíme číslo dne v týdnu, které uložíme do struktury DATETIME.
|
Připravíme proměnné pro Juliánský kalendář - proměnná "b" (v registru EBX) představující číslo století bude nulová, proměnná "c" (v registru ECX) s číslem absolutního dne se opraví posunem do kladných oblastí. Současně se odečte minimální den kalendáře, aby se opravil posun získaný na začátku funkce AbsToDateTime.
|
Nyní se provede příprava pro Gregoriánský kalendář (datum 15. října 1582 a vyšší). Opraví se počet dnů v proměnné "c" (v registru ECX) podle Gregoriánského kalendáře (10 dnů skok v datu a oprava rozdílně započítaných přechodných staletí). Do proměnné "b" (registr EBX) se připraví číslo století ("b=(c*4 + 3)/146097)") - namísto dělení číslem 146097 se použije rychlejší operace násobení převrácenou hodnotou (tj. 8000 0000 0000h/146097, zaokrouhleno nahoru). Po rotaci o 15 bitů doprava obdržíme číslo století. Po přepočtu století zpět na dny a odečtením od původního čísla dne ("c = c - (b*146097)/4") obdržíme číslo dne v aktuálním století (s počátkem roku 1. března).
|
Pokračuje část společná pro oba kalendáře. Do proměnné "d" (registr EDX) připravíme číslo dne ve století ("d = (c*4 + 3)/1461"). Namísto dělení použijeme rychlejší operaci násobení převrácenou hodnotou (tj. číslem 80 0000 0000h/1461, zaokrouhleno nahoru), výsledek v registru EDX opravíme rotací o 7 bitů doprava.
|
Přepočtem století na roky a přičtením roku ve století obdržíme číslo roku, zatím s přičteným počátkem 40000 ("b = b*100 + d").
|
Do proměnné "c" (registr ECX) připravíme číslo dne v roce s počátkem 1. března s použitím dne ve století ("c = c - (1461*d)/4").
|
Do proměnné "d" (registr EDX) připravíme číslo měsíce v roce s počátkem v březnu ("d = (c*5 + 2)/153"). Namísto dělením číslem 153 použijeme rychlejší operaci násobení převrácenou hodnotou (číslem 80 0000 0000h/153, zaokrouhleno nahoru). Výsledek obdržíme v registru EDX po rotaci o 7 bitů doprava.
|
Při výpočtu dne v měsíci přepočteme nejdříve číslo měsíce na počet dnů od pomocného začátku roku (kterým je 1. březen, "(153*d + 2)/5"). Namísto dělení číslem 5 použijeme rychlejší násobení převrácenou hodnotou (tj. číslem 100000000h/5, zaokrouhleno nahoru).
|
Při výpočtu roku si připravíme nejdříve pomocný příznak indikující, zda měsícem je leden nebo únor (číslo měsíce je 10 nebo 11, "if (d >= 10) e = 1; else e = 0;"). Příznak použijeme ve výpočtu čísla roku ("year = b - 40000 + e").
|
Nakonec vypočteme číslo měsíce ("month = d + 3 + ((-12) & (-e))") a výsledné datum uložíme do struktury DATETIME.
Obsah / Utility / CALENDAR / Konverze absolutního času na datum a čas