Code : Tout sélectionner
; DWORD AbsDayNumToDate(DWORD N, DWORD Gregorian, DWORD* Y, DWORD* M, DWORD* D)
;
; This function converts the absolute day number N = 1, 2, ..., 2^32-1 to the adequate date (for the chosen calendar).
;
; Parameters:
; N - absolute day number,
; Gregorian - chosen calendar (0 - Julian, 1 - Gregorian),
; Y - pointer to variable where the calculated year number will be stored,
; M - pointer to variable where the calculated month number will be stored,
; D - pointer to variable where the calculated day number will be stored.
;
; Returned values:
; * 0 for the valid parameters (N, Gregorian),
; * -1 in opposite case.
Procedure AbsDayNumToDate( N.l, Gregorian.l, Y.l, M.l, D.l)
;PUSHFD
;PUSH ebx ecx edx
Protected.l tmpeax, tmpecx, tmpedx, tmpeflags, tmp
EnableASM
CMP N, 0 ; N <> 0 ; l'année n'existe pas
JE l_absdaynumtodate_error ;
TEST Gregorian, -2 ; 0 <= Gregorian <= 1
JNZ l_absdaynumtodate_error ;
XOR ecx, ecx ; ecx := 0
MOV eax, N ; eax := N - 1
DEC eax ;
CMP Gregorian, 0
JE l_absdaynumtodate_julian
gregorian:
CMP eax, 1
JA l_absdaynumtodate_nextdays ;Jump short if above (CF=0 and ZF=0).
; 0 <= eax <= 1 (1 <= N <= 2)
MOV ecx, M ; M := 12
MOV dword [ecx], 12 ;
ADD eax, 30 ; eax := eax + 30 = N - 1 + 30 = N + 29
MOV ecx, D ; D := eax = N + 29
MOV [ecx], eax ;
MOV ecx, -5844001 ; -k*G - 1 ; ecx := -kG - 1 = -5844001
; Global k = 30
; Global J = 194796 ; The constants J and G are equal to the numbers of the complete years
; Global G = 194800 ; of the Julian and Gregorian calendars respectively contained in the
; time interval given by "Great Cycle" T.
JMP l_absdaynumtodate_yearr
nextdays: ; eax > 1 (N > 2)
SUB eax, 2 ; eax := eax - 2 = N - 1 - 2 = N - 3
XOR edx, edx ;
; Global C1 = 365 ; Number of days in a normal year.
; Global C4 = 4*C1 + 1 = 1461 ; Number of days in the 4-year cycle (base cycle of the Julian calendar).
; Global C100 = 25*C4 - 1 = 36524; Number of days in a "normal" century in the Gregorian calendar
; ; (i.e. century ending with a normal, 365-day, year).
; Global C400 = 4*C100 + 1 = 146097 ; Number of days in the complete 400-year cycle of the Gregorian calendar.
MOV ecx, 146097 ;C400 ; eax := E(eax / C400) = E((N - 3) / C400)
DIV ecx ; edx := eax mod C400 = (N - 3) mod C400
LEA eax, [eax + 4*eax] ; eax := 5*eax = 5*E((N - 3) / C400)
LEA eax, [eax + 4*eax] ; eax := 5*eax = 5*(5*E((N - 3) / C400)) =
; = 25*E((N - 3) / C400)
SHL eax, 4 ; eax := 16*eax = 16*(25*E((N - 3) / C400)) =
; = 400*E((N - 3) / C400)
XCHG ecx, eax ; ecx := eax = 400*E((N - 3) / C400)
XCHG eax, edx ; eax := edx = (N - 3) mod C400
centuries: ;
CMP eax, 36524 ; C100
JB l_absdaynumtodate_julian ;Jump short if below (CF=1).
ADD ecx, 100
SUB eax, 36524 ; C100
CMP eax, 36524 ; C100 ; (eax, ecx) := P(eax, ecx) =
JB l_absdaynumtodate_julian ; = P((N - 3) mod C400, 400*E((N - 3) / C400)) =
; = (N100, Y100)
ADD ecx, 100
SUB eax, 36524 ; C100
CMP eax, 36524 ; C100
JB l_absdaynumtodate_julian
ADD ecx, 100
SUB eax, 36524 ; C100
julian:
; /
; | (N - 1, 0) ; Gregorian = 0
; (N100, Y100) = (eax, ecx) = <
; | P((N - 3) mod C400, 400*E((N - 3) / C400)) ; Gregorian = 1
; \
PUSH ecx
XOR edx, edx
MOV ecx, 1461 ; C4 ; eax := E(eax / C4) = E(N100 / C4)
DIV ecx ; edx := eax mod C4 = N100 mod C4
POP ecx
SHL eax, 2 ; eax := 4*eax = 4*E(N100 / C4)
ADD ecx, eax ; ecx := ecx + eax = Y100 + 4*E(N100 / C4)
years:
INC ecx
CMP edx, 365 ; C1
JB l_absdaynumtodate_md
SUB edx, 365 ; C1
INC ecx ; (edx, ecx) := Q(edx, ecx) =
CMP edx, 365 ; C1 ; = Q(N100 mod C4, Y100 + 4*E(N100 / C4)) =
JB l_absdaynumtodate_md ; = (N', Y*)
SUB edx, 365 ; C1
INC ecx
CMP edx, 365 ; C1
JB l_absdaynumtodate_md
SUB edx, 365 ; C1
INC ecx
md:
INC edx ; edx := edx + 1 = N' + 1
;sauvegarde
MOV tmpeax, eax
MOV tmpecx, ecx
MOV tmpedx, edx
IsLeapYear(tmpecx, Gregorian) ; eax := IsLeapYear(ecx=year, Gregorian) =
; = IsLeapYear(Y*, Gregorian)
MOV tmpeax, eax
;DayNumToMD(n.l, LeapYearFlag.l, M.l, D.l)
DayNumToMD(tmpedx, tmpeax, M, D)
MOV ecx, tmpecx
MOV edx, tmpedx
CMP Gregorian, 0
JE l_absdaynumtodate_julianyears
gregorianyears:
SUB ecx, 120 ;k*(G - J) ;k*(G - J)=180
; ecx := ecx - kJ - k(G - J)[Gregorian = 1] =
julianyears: ; = Y* - kJ - k(G - J)[Gregorian = 1] =
SUB ecx, 5843880 ;k*J ; = Y';k*J=5843880
CMP ecx, 0
JG l_absdaynumtodate_yearr
; ecx <= 0 (Y' <= 0)
DEC ecx ; ecx := ecx - 1 = Y' - 1 = Y' - [Y' <= 0]
yearr:
MOV eax, Y ; Y := ecx
MOV [eax], ecx
XOR eax, eax
JMP l_absdaynumtodate_theend
error:
MOV eax, -1
theend:
;POP edx ecx ebx
;POPFD
DisableASM
ProcedureReturn
EndProcedure