News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Julian Day to Gregorian date and back

Started by Jimg, September 30, 2009, 03:15:53 PM

Previous topic - Next topic

Jimg

I recently needed routines to convert day/month/year to a day number for plotting, and back for anotation.  I didn't immediately find rountines I liked, so I converted some Fortran code from a 1968 ACM publication.
Anything I have done here is free for all uses.

; date routines from
; "A machine algorithm for processing calendar dates"
; Henry F. Fliegel and Thomas C. Van Flandern
; Commun. ACM 11(10): 657 (1968)

; valid for all Gregorian calendar dates after November 23, -4713.
GetJulianDay proc gjdDay,gjdMonth,gjdYear  ; returns (Julian) day number in eax
;      JD=DD-32075+1461*(YYYY+4800+(MM-14)/12)/4
;     ,         +367*(MM-2-((MM-14)/12)*12)/12
;     ,        -3*((YYYY+4900+(MM-14)/12)/100)/4
;
    push esi    ; use for common term  (MM-14)/12 which will be -1 or zero
    xor eax,eax ; (MM-14)/12 ==  if MM<2 then = -1, else = 0
    .if gjdMonth<3
        dec eax  ;-1
    .endif
    mov esi,eax   ; save common amount
    add eax,4800    ;DD-32075+1461*(YYYY+4800+(MM-14)/12)/4
    add eax,gjdYear
    imul eax,1461
    shr eax,2
    add eax,gjdDay
    sub eax,32075
    mov ecx,eax     ; save partial
   
    mov eax,esi   ;+367*(MM-2-((MM-14)/12)*12)/12
    imul eax,-12
    sub eax,2
    add eax,gjdMonth
    imul eax,367
    mov edx,0AAAAAAABh ; divide by 12
    mul edx
    shr edx,03h
    add ecx,edx
   
    mov eax,esi   ;-3*((YYYY+4900+(MM-14)/12)/100)/4
    add eax,4900
    add eax,gjdYear
    mov edx,051EB851Fh  ; divide by 100
    mul edx
    shr edx,05h
    lea eax,[edx+2*edx] ; * 3   
    shr eax,2
    neg eax
    add eax,ecx

    pop esi
    ret
GetJulianDay endp

align 4
GetDMY proc gdmyJulianDay ; returns eax=day, edx=month, ecx=year
;      INTEGER JD,YYYY,MM,DD,L,N
;      L=JD+68569
;      N=4*L/146097
;      L=L-(146097*N + 3)/4
;      YYYY=4000*(L+1)/1461001
;      L=L-1461*YYYY/4+31
;      MM=80*L/2447
;      DD=L-2447*MM/80
;      L=MM/11
;      MM=MM + 2 - 12*L
;      YYYY=100*(N-49) + YYYY + L   

;   We will use ecx to contain L, esi to contain N
    local gdmyYYYY,gdmyMM
    push esi        ; will contain N throughout
    mov eax,gdmyJulianDay  ; L=JD+68569
    add eax,68569
    mov ecx,eax     ; keep L in ecx

    shl eax,2       ; N=4*L/146097
    mov edx,0396B06BDh  ; div 146097
    mul edx
    shr edx,0Fh
    mov eax,edx ; edx = quotient in magic divide 
    mov esi,eax

    imul eax,146097 ; L=L-(146097*N + 3)/4
    add eax,3
    shr eax,2
    sub ecx,eax

    mov eax,ecx     ; YYYY=4000*(L+1)/1461001
    add eax,1
    imul eax,4000
    mov edx,0B7BBE2DDh  ;div 1461001
    mul edx
    shr edx,014h
    mov eax,edx

    mov gdmyYYYY,eax
   
    imul eax,1461   ; L=L-1461*YYYY/4+31
    shr eax,2
    neg eax
    add eax,31
    add ecx,eax
   
    mov eax,ecx     ; MM=80*L/2447
    imul eax,80
    mov edx,0D641E8C7h  ; div 2447
    mul edx
    shr edx,0Bh
    mov eax,edx
    mov gdmyMM,eax

    imul eax,2447   ; DD=L-2447*MM/80
    mov edx,0CCCCCCCDh  ; div 80
    mul edx
    shr edx,06h
    neg edx
    add edx,ecx
    push edx        ; save DD
   
    mov eax,gdmyMM     ; L=MM/11
    mov edx,0BA2E8BA3h  ; div 11
    mul edx
    shr edx,03h
    mov eax,edx
    mov ecx,eax
   
    imul eax,-12     ; MM=MM + 2 - 12*L
    add eax,2
    add eax,gdmyMM
    mov gdmyMM,eax
   
    mov eax,esi       ; YYYY=100*(N-49) + YYYY + L       
    sub eax,49
    imul eax,100
    add eax,gdmyYYYY
    add ecx,eax     ; final Year returned in ecx
    pop eax         ; get back DD.  final day returned in eax
    mov edx,gdmyMM     ; final month returned in edx

    pop esi
    ret
GetDMY endp


This code is only slightly optimized, so feel free to post improvements.