Ładowanie
Angielski
Rosyjski
Strona domowa Mikołaja Hajduka

Biblioteka funkcji kalendarzowych

I
nspiracją do stworzenia biblioteki zawierającej funkcje obsługujące kalendarze juliański oraz gregoriański było moje zainteresowanie historią, w szczególności historią starożytną. Ponadto było to ciekawe wyzwanie z punktu widzenia matematycznego i programistycznego. Należało najpierw stworzyć model matematyczny funkcji kalendarzowych, a następnie przełożyć tenże model na język asemblera FASM. W początkowym zamierzeniu funkcje kalendarzowe miały obejmować okres czasu od początku naszej ery (w przypadku kalendarza juliańskiego) oraz od 15.X.1582 (dla kalendarza gregoriańskiego) aż do pewnego dnia odległego o 11 mln lat w przyszłości. Jednak wiele dat interesujących historyków leży w odcinku czasowym poprzedzającym początek naszej ery, w związku z czym zaistniała potrzeba przebudowy funkcji kalendarzowych w taki sposób, aby obejmowały one zakres czasowy 11 mln lat, w środku którego leży początek naszej ery. Procedury obliczania czasu zostały rozszerzone wstecz poza datę wprowadzenia kalendarza gregoriańskiego oraz 1.I.1 dla kalendarza juliańskiego (tak otrzymane kalendarze nazywane są proleptycznymi), dzięki czemu można dokonywać swobodnej konwersji między tymi systemami.

Biblioteka została opisana w trzech językach (polskim, angielskim oraz rosyjskim) po to, by krąg jej odbiorców był możliwie jak najszerszy.

Możliwości funkcji bibliotecznych

Funkcje eksportowane przez bibliotekę DLL oferują następujące możliwości:

  • funkcje obsługują odcinek czasu o długości ponad 11 milionów lat:
    • od 1.I.5843880 p.n.e. do 3.VIII.5915100 dla kalendarza juliańskiego,
    • od 30.XII.5844001 p.n.e. do 17.I.5915222 dla kalendarza gregoriańskiego,
  • wygodna konwersja dat pomiędzy kalendarzami juliańskim i gregoriańskim w obsługiwanym okresie czasu,
  • określanie dnia tygodnia odpowiadającego danej dacie,
  • obliczanie porządkowego numeru dnia w roku na podstawie danego numeru miesiąca i dnia w miesiącu,
  • określanie przestępności roku w danym kalendarzu,
  • obliczanie tzw. "absolutnego" numeru dnia odpowiadającego danej dacie, dzięki temu łatwo jest obliczać ilość dni które upłynęły pomiędzy dwiema wybranymi datami.

Krótki opis funkcji kalendarzowych

Biblioteka zawiera 8 funkcji przeznaczonych do operowania na datach:

  • DayOfWeek - określa dzień tygodnia odpowiadający danej dacie,
  • IsLeapYear - określa przestępność danego roku w zależności od rodzaju kalendarza,
  • MDToDayNum - oblicza numer porządkowy danego dnia w roku (z uwzględnieniem przestępności),
  • DayNumToMD - przekształca numer porządkowy danego dnia w roku w odpowiadające mu numery miesiąca i dnia w miesiącu,
  • DateToAbsDayNum - oblicza absolutny numer dnia odpowiadający danej dacie,
  • AbsDayNumToDate - przekształca absolutny numer dnia w odpowiadającą mu datę wybranego kalendarza,
  • GregorianToJulian - przekształca daną datę kalendarza gregoriańskiego w odpowiadającą jej datę kalendarza juliańskiego,
  • JulianToGregorian - przekształca daną datę kalendarza juliańskiego w odpowiadającą jej datę kalendarza gregoriańskiego.

Źródło

Poniżej przedstawiona jest zawartość pliku źródłowego biblioteki:

; Biblioteka funkcji kalendarzowych napisana w asemblerze FASM.
;
; Możliwości:
;	* funkcje obsługują odcinek czasu o długości ponad 11 milionów lat:
;		- od 1.I.5843880 p.n.e. do 3.VIII.5915100 dla kalendarza
;		  juliańskiego,
;		- od 30.XII.5844001 p.n.e. do 17.I.5915222 dla kalendarza
;		  gregoriańskiego,
;	* wygodna konwersja dat pomiędzy kalendarzami juliańskim i gregoriańskim
;	  w obsługiwanym okresie czasu,
;	* określanie dnia tygodnia odpowiadającego danej dacie,
;	* obliczanie porządkowego numeru dnia w roku na podstawie danego numeru
;	  miesiąca i dnia w miesiącu,
;	* określanie przestępności roku w danym kalendarzu,
;	* obliczanie tzw. "absolutnego" numeru dnia odpowiadającego danej dacie,
;	  dzięki temu łatwo jest obliczać ilość dni które upłynęły pomiędzy
;	  dwiema wybranymi datami.
;
; (C) Mikołaj Hajduk, 16.06.2008.
;
format PE GUI 4.0 DLL
entry DllEntryPoint

include 'win32a.inc'

; Definicje stałych używanych przez funkcje biblioteczne.
;
C1	= 365			; Ilość dni roku zwykłego.

C4	= 4*C1 + 1		; Ilość dni w cyklu czteroletnim (podstawowym cyklu kalendarza 
				; juliańskiego).

C100	= 25*C4 - 1		; Ilość dni w "normalnym" stuleciu kalendarza gregoriańskiego
				; (tj. stuleciu kończącym się rokiem o długości 365 dni).

C400	= 4*C100 + 1		; Ilość dni w pełnym cyklu 400-letnim kalendarza gregoriańskiego.

k	= 30

J	= 194796		; Stałe J oraz G przechowują ilości pełnych lat odpowiednio kalendarzy 
G	= 194800		; juliańskiego i gregoriańskiego zawartych w odcinku czasu określonego
				; "Wielkim Cyklem" T.


section '.data' data readable writeable

; Tablica przechowująca długości miesięcy roku zwykłego i przestępnego.
;
MonthLen	db 31,  28,  31,  30,  31,  30,  31,  31,  30,  31,  30,  31
		db 31,  29,  31,  30,  31,  30,  31,  31,  30,  31,  30,  31

; Tablica zawierająca wartości funkcji 'DaySum' dla wszystkich par 
; (numer miesiąca, flaga przestępności roku).
;
DaySum		dw  0,  31,  59,  90, 120, 151, 181, 212, 243, 273, 304, 334
		dw  0,  31,  60,  91, 121, 152, 182, 213, 244, 274, 305, 335


section '.code' code readable executable

proc	DllEntryPoint, hinstDLL, fdwReason, lpvReserved
	mov	eax, TRUE
	ret
endp

; DWORD DayOfWeek(DWORD Y, DWORD M, DWORD D, DWORD Gregorian)
;
; Funkcja określa dzień tygodnia odpowiadający danej dacie. Każdemu dniowi tygodnia przyporządkowany jest 
; odpowiedni numer: 0 - niedziela, 1 - poniedziałek, 2 - wtorek, 3 - środa, 4 - czwartek, 5 - piątek, 6 - sobota.
;
; Parametry:
;	Y - rok,
;	M - miesiąc,
;	D - dzień,
;	Gregorian - rodzaj kalendarza (0 - juliański, 1 - gregoriański).
;
; Wartości zwracane:
;	* 0, 1, ..., 6, jeśli data jest prawidłowa,
;	* -1 dla nieprawidłowych danych.
;
proc	DayOfWeek, Y, M, D, Gregorian

	pushfd
	push	ebx edx

	stdcall DateToAbsDayNum, [Y], [M], [D], [Gregorian]		; eax := N
	test	eax, eax
	jz	.Error

	mov	ebx, 7							;
	xor	edx, edx						;
	add	eax, 5							; edx := (eax + 5) mod 7 = (N + 5) mod 7
	adc	edx, edx						;
	div	ebx							;

	xchg	eax, edx						; eax := edx
	jmp	.End

	.Error:
		mov	eax, -1
	.End:

	pop	edx ebx
	popfd

	ret
endp

; DWORD IsLeapYear(DWORD Y, DWORD Gregorian)
;
; Funkcja określa przestępność danego roku w zależności od rodzaju kalendarza.
;
; Parametry:
;	Y - rok,
;	Gregorian - rodzaj kalendarza (0 - juliański, 1 - gregoriański).
;
; Wartości zwracane:
;	* 1, jeśli rok Y jest przestępny, 0 - w przeciwnym wypadku,
;	* -1 dla nieprawidłowych danych.
;
proc	IsLeapYear, Y, Gregorian

	pushfd
	push	ebx edx

	.CheckParameters:
		test	[Gregorian], -2					; 0 <= Gregorian <= 1
		jnz	.Error						;

	.IsYNegative:
		mov	eax, [Y]					; eax := Y
		test	eax, eax
		jz	.Error
		jns	.CheckCalendar
									; eax < 0 (Y < 0)
									;
		inc	eax						; eax := eax + 1
		neg	eax						; eax := -eax = -(Y + 1) = -Y - 1 =
									;      = |Y| - [Y < 0] = Y'

	.CheckCalendar:
		cmp	[Gregorian], 0
		je	.mod4

	.Gregorian:
		xor	edx, edx					; eax := E(eax / 100) = E(Y' / 100)
		mov	ebx, 100					; edx := eax mod 100 = Y' mod 100
		div	ebx						; 

		test	edx, edx
		jz	.mod4

		mov	eax, edx					; eax := edx = Y' mod 100
									; 
									; {(Y' mod 100) mod 4 = Y' mod 4} 

	.mod4:
		shr	eax, 1						; eax := E(eax / 2); CF := eax mod 2
		jc	.Result						; 

		shr	eax, 1						; eax := E(eax / 2); CF := eax mod 2
		jmp	.Result						;

	.Error:
		mov	eax, -1
		jmp	.End

	.Result:
		setnc	al						; eax := not CF
		movzx	eax, al						;

	.End:

	pop	edx ebx
	popfd

	ret
endp

; DWORD MDToDayNum(DWORD M, DWORD D, DWORD LeapYearFlag)
;
; Funkcja oblicza numer porządkowy danego dnia w roku (z uwzględnieniem przestępności).
;
; Parametry:
;	M - miesiąc,
;	D - dzień,
;	LeapYearFlag - flaga określająca przestępność roku (0 - rok normalny, 1 - rok przestępny).
;
; Wartości zwracane:
;	* 1, 2, ..., 365 dla roku normalnego, 1, 2, ..., 366 dla roku przestępnego,
;	* -1 dla nieprawidłowych danych.
;
proc	MDToDayNum, M, D, LeapYearFlag

	pushfd
	push	ebx edx

	.LeapYearFlag:
		test	[LeapYearFlag], -2				; 0 <= LeapYearFlag <= 1
		jnz	.Error						;

	.Month:
		cmp	[M], 1						;
		jb	.Error						; 1 <= M <= 12
		cmp	[M], 12						;
		ja	.Error						;

	.Day:
		cmp	[D], 1						; D >= 1
		jb	.Error						;

		mov	ebx, [LeapYearFlag]				; ebx := LeapYearFlag
		lea	ebx, [ebx + 2*ebx]				; ebx := 3*ebx = 3*LeapYearFlag
		shl	ebx, 2						; ebx := 4*ebx = 12*LeapYearFlag

		mov	edx, [M]					; eax := MonthLen[M - 1 + 12*LeapYearFlag]
		movzx	eax, [MonthLen - 1 + ebx + edx]			;

		cmp	[D], eax					; D <= MonthLen[M - 1 + 12*LeapYearFlag]
		ja	.Error						;

	.CalculateDayNum:
		shl	ebx, 1						; ebx := 2*ebx = 24*LeapYearFlag
		movzx	eax, [DaySum - 2 + ebx + 2*edx]			; eax := DaySum(M, LeapYearFlag)
		add	eax, [D]					; eax := eax + D = DaySum(M, LeapYearFlag) + D 
		jmp	.End

	.Error:
		mov	eax, -1

	.End:

	pop	edx ebx
	popfd

	ret
endp

; DWORD DayNumToMD(DWORD n, DWORD LeapYearFlag, DWORD* M, DWORD* D)
;
; Funkcja przekształca numer porządkowy danego dnia w roku w odpowiadające mu numery miesiąca 
; i dnia w miesiącu. Rezultat w istotny sposób zależy od wartości flagi przestępności roku.
;
; Parametry:
;	n - numer porządkowy dnia w roku,
;	LeapYearFlag - flaga określająca przestępność roku (0 - rok normalny, 1 - rok przestępny),
;	M - wskaźnik na zmienną, w której umieszczany jest obliczony numer miesiąca,
;	D - wskaźnik na zmienną, w której umieszczany jest obliczony numer dnia. 
;
; Wartości zwracane:
;	* 0 dla prawidłowych danych (n, LeapYearFlag),
;	* -1 w przeciwnym wypadku.
;
proc	DayNumToMD, n, LeapYearFlag, M, D

	pushfd
	push	ebx ecx edx

	.CheckParameters:
		test	[LeapYearFlag], -2				; 0 <= LeapYearFlag <= 1
		jnz	.Error

		cmp	[n], 1						; n >= 1
		jb	.Error						;

		mov	eax, 365					;
		add	eax, [LeapYearFlag]				; eax := 365 + LeapYearFlag
		cmp	[n], eax					; n <= eax
		ja	.Error						;

	.CalculateMD:
		mov	ebx, [LeapYearFlag]				; ebx := LeapYearFlag
		lea	ebx, [ebx + 2*ebx]				; ebx := 3*ebx = 3*LeapYearFlag
		shl	ebx, 3						; ebx := 8*ebx = 24*LeapYearFlag

		mov	ecx, 12						;
									;
		.Loop:							; ecx := max{i; 1 <= i <= 12, DaySum(i, LeapYearFlag) < n} = m
			movzx	edx, [DaySum - 2 + ebx + 2*ecx]		;
			cmp	[n], edx				; edx := DaySum(m, LeapYearFlag)
			ja	.LoopEnd				;
			loop	.Loop					;

		.LoopEnd:
			mov	eax, [M]				; M := ecx = m
			mov	[eax], ecx				;

			mov	ecx, [n]				; ecx := n
			sub	ecx, edx				; ecx := ecx - edx = n - DaySum(m, LeapYearFlag)

			mov	eax, [D]				; D := ecx
			mov	[eax], ecx				;

			xor	eax, eax

			jmp	.End

	.Error:
		mov	eax, -1

	.End:

	pop	edx ecx ebx
	popfd

	ret
endp

; DWORD DateToAbsDayNum(DWORD Y, DWORD M, DWORD D, DWORD Gregorian)
;
; Funkcja oblicza absolutny numer dnia odpowiadający danej dacie.
;
; Parametry:
;	Y - rok,
;	M - miesiąc,
;	D - dzień,
;	Gregorian - rodzaj kalendarza (0 - juliański, 1 - gregoriański).
;
; Wartości zwracane:
;	* 1, 2, ..., 2^32-1 dla prawidłowej daty danego kalendarza,
;	* 0 dla nieprawidłowych danych.
;
proc	DateToAbsDayNum, Y, M, D, Gregorian

	pushfd
	push	ebx ecx edx

	test	[Gregorian], -2						; 0 <= Gregorian <= 1
	jnz	.Error							;

	stdcall	IsLeapYear, [Y], [Gregorian]				;
	cmp	eax, -1							; eax := IsLeapYear(Y, Gregorian)
	je	.Error							;

									; Y <> 0

	mov	ebx, eax						; ebx := eax

	stdcall	MDToDayNum, [M], [D], ebx				;
	cmp	eax, -1							; eax := MDToDayNum(M, D, ebx) = n
	je	.Error							;

	mov	ecx, [Y]						;
	cmp	ecx, 0							; ecx := Y
	jg	.CalculateDayNum					;

	inc	ecx							; Y < 0
									; ecx := ecx + 1 = Y + 1 = Y + [Y < 0]

	.CalculateDayNum:
		add	ecx, k*J					; 
		cmp	[Gregorian], 0					; ecx := ecx + kJ + k(G-J)[Gregorian = 1] =
		je	.Yprim0						;      = Y + [Y < 0] + kJ + k(G-J)[Gregorian = 1] = Y'
		add	ecx, k*(G-J)					; 

	.Yprim0:
		cmp	ecx, 0						;
		jne	.YprimPositive					; Y' = 0
		sub	eax, 364					; eax := eax - 364 = n - 364
		jmp	.End						;

	.YprimPositive:							; Y' > 0
									;
		dec	ecx						; ecx := ecx - 1 = Y' - 1
		mov	ebx, eax					; ebx := eax = n

		mov	eax, 365					; eax := 365
		mul	ecx						; eax := 365 * ecx = 365(Y' - 1)
		
		shr	ecx, 2						; ecx := E(ecx / 4) = E((Y' - 1) / 4)
		add	eax, ecx					; eax := eax + ecx = 365(Y' - 1) + E((Y' - 1) / 4)
		add	eax, ebx					; eax := eax + ebx = eax + n =
									;      = 365(Y' - 1) + E((Y' - 1) / 4) + n

		cmp	[Gregorian], 0
		jz	.End

	.Gregorian:
		push	eax						; X := eax

		xor	edx, edx					;
		mov	eax, ecx					; eax := ecx = E((Y' - 1) / 4)
		mov	ebx, 25						;
		div	ebx						; eax := E(eax / 25) = E(E((Y' - 1) / 4) / 25) =
									;      = E((Y' - 1) / 100)

		mov	ecx, eax					; ecx := eax = E((Y' - 1) / 100)
		pop	eax						; eax := X = 365(Y' - 1) + E((Y' - 1) / 4) + n

		sub	eax, ecx					; eax := eax - ecx = 365(Y' - 1) + E((Y' - 1) / 4) + n -
									;                    - E((Y' - 1) / 100)

		shr	ecx, 2						; ecx : = E(ecx / 4) = E(E((Y' - 1) / 100) / 4) =
									;       = E((Y' - 1) / 400)


		add	eax, ecx					; eax := eax + ecx = 365(Y' - 1) + E((Y' - 1) / 4) + n -
									;                    - E((Y' - 1) / 100) + E((Y' - 1) / 400)

		add	eax, 2						; eax := eax + 2 = 365(Y' - 1) + E((Y' - 1) / 4) + n -
									;                  - E((Y' - 1) / 100) + E((Y' - 1) / 400) + 2 =
									;                = N

		jmp	.End

	.Error:
		xor	eax, eax

	.End:

	pop	edx ecx ebx
	popfd

	ret
endp

; DWORD AbsDayNumToDate(DWORD N, DWORD Gregorian, DWORD* Y, DWORD* M, DWORD* D)
;
; Funkcja przekształca absolutny numer dnia N = 1, 2, ..., 2^32-1 w odpowiadającą mu datę
; wybranego kalendarza.
;
; Parametry:
;	N - absolutny numer dnia,
;	Gregorian - rodzaj kalendarza (0 - juliański, 1 - gregoriański),
;	Y - wskaźnik na zmienną, w której umieszczany jest obliczony numer roku,
;	M - wskaźnik na zmienną, w której umieszczany jest obliczony numer miesiąca,
;	D - wskaźnik na zmienną, w której umieszczany jest obliczony numer dnia.
;
; Wartości zwracane:
;	* 0 dla prawidłowych danych (N, Gregorian),
;	* -1 w przeciwnym wypadku.
;
proc	AbsDayNumToDate, N, Gregorian, Y, M, D

	pushfd
	push	ebx ecx edx

	cmp	[N], 0							; N <> 0
	je	.Error							;

	test	[Gregorian], -2						; 0 <= Gregorian <= 1
	jnz	.Error							;

	xor	ecx, ecx						; ecx := 0
	
	mov	eax, [N]						; eax := N - 1
	dec	eax							;

	cmp	[Gregorian], 0
	je	.Julian

	.Gregorian:
		cmp	eax, 1
		ja	.NextDays

									; 0 <= eax <= 1 (1 <= N <= 2)

		mov	ebx, [M]					; M := 12
		mov	dword [ebx], 12					;

		add	eax, 30						; eax := eax + 30 = N - 1 + 30 = N + 29 

		mov	ebx, [D]					; D := eax = N + 29
		mov	[ebx], eax					;

		mov	ecx, -k*G - 1					; ecx := -kG - 1

		jmp	.ReturnY

	.NextDays:							; eax > 1 (N > 2)

		sub	eax, 2						; eax := eax - 2 = N - 1 - 2 = N - 3

		xor	edx, edx					;
		mov	ebx, C400					; eax := E(eax / C400) = E((N - 3) / C400)
		div	ebx						; 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, C100				;
			jb	.Julian					;
									;
			add	ecx, 100				;
			sub	eax, C100				;
									;
			cmp	eax, C100				; (eax, ecx) := P(eax, ecx) = 
			jb	.Julian					;             = P((N - 3) mod C400, 400*E((N - 3) / C400)) =
									;             = (N100, Y100)
			add	ecx, 100				;
			sub	eax, C100				;
									;
			cmp	eax, C100				;
			jb	.Julian					;
									;
			add	ecx, 100				;
			sub	eax, C100				;

	.Julian:
									;                             /
									;                             |  (N - 1, 0)                                 ; Gregorian = 0
									; (N100, Y100) = (eax, ecx) = <
									;                             |  P((N - 3) mod C400, 400*E((N - 3) / C400)) ; Gregorian = 1
									;                             \

		xor	edx, edx					;
		mov	ebx, C4						; eax := E(eax / C4) = E(N100 / C4)
		div	ebx						; edx := eax mod C4 = N100 mod C4

		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, C1					;
			jb	.MD					;
									;
			sub	edx, C1					;
									;
			inc	ecx					; (edx, ecx) := Q(edx, ecx) =
			cmp	edx, C1					;             = Q(N100 mod C4, Y100 + 4*E(N100 / C4)) =
			jb	.MD					;             = (N', Y*)
									;
			sub	edx, C1					;
									;
			inc	ecx					;
			cmp	edx, C1					;
			jb	.MD					;
									;
			sub	edx, C1					;
									;
			inc	ecx					;

	.MD:
		inc	edx						; edx := edx + 1 = N' + 1

		stdcall	IsLeapYear, ecx, [Gregorian]			; eax := IsLeapYear(ecx, Gregorian) =
									;      = IsLeapYear(Y*, Gregorian)

		stdcall	DayNumToMD, edx, eax, [M], [D]			; eax := DayNumToMD(edx, eax, M, D) =
									;      = DayNumToMD(N' + 1, IsLeapYear(Y*, Gregorian), M, D)

		cmp	[Gregorian], 0
		je	.JulianYears

		.GregorianYears:					;
			sub	ecx, k*(G - J)				;
									; ecx := ecx - kJ - k(G - J)[Gregorian = 1] =
		.JulianYears:						;      = Y* - kJ - k(G - J)[Gregorian = 1] = 
			sub	ecx, k*J				;      = Y'

			cmp	ecx, 0
			jg	.ReturnY
									; ecx <= 0 (Y' <= 0)

			dec	ecx					; ecx := ecx - 1 = Y' - 1 = Y' - [Y' <= 0]

		.ReturnY:
			mov	eax, [Y]				; Y := ecx
			mov	[eax], ecx				;

		xor	eax, eax
		jmp	.End

	.Error:
		mov	eax, -1

	.End:

	pop	edx ecx ebx
	popfd

	ret
endp

; DWORD GregorianToJulian(DWORD Yg, DWORD Mg, DWORD Dg, DWORD* Yj, DWORD* Mj, DWORD* Dj)
;
; Funkcja przekształca daną datę kalendarza gregoriańskiego w odpowiadającą jej datę kalendarza juliańskiego.
;
; Parametry:
;	Yg - rok daty gregoriańskiej,
;	Mg - miesiąc daty gregoriańskiej,
;	Dg - dzień daty gregoriańskiej,
;	Yj - wskaźnik na zmienną, w której umieszczany jest numer roku daty juliańskiej,
;	Mj - wskaźnik na zmienną, w której umieszczany jest numer miesiąca daty juliańskiej,
;	Dj - wskaźnik na zmienną, w której umieszczany jest numer dnia daty juliańskiej.
;
; Wartości zwracane:
;	* 0 dla prawidłowej daty gregoriańskiej,
;	* -1 w przeciwnym wypadku.
;
proc	GregorianToJulian, Yg, Mg, Dg, Yj, Mj, Dj

	.GregorianToNum:
		stdcall DateToAbsDayNum, [Yg], [Mg], [Dg], 1
		test	eax, eax
		jz	.Error

	.NumToJulian:
		stdcall AbsDayNumToDate, eax, 0, [Yj], [Mj], [Dj]
		jmp	.End

	.Error:
		mov	eax, -1

	.End:

	ret
endp

; DWORD JulianToGregorian(DWORD Yj, DWORD Mj, DWORD Dj, DWORD* Yg, DWORD* Mg, DWORD* Dg)
;
; Funkcja przekształca daną datę kalendarza juliańskiego w odpowiadającą jej datę kalendarza gregoriańskiego.
;
; Parametry:
;	Yj - rok daty juliańskiej,
;	Mj - miesiąc daty juliańskiej,
;	Dj - dzień daty juliańskiej,
;	Yg - wskaźnik na zmienną, w której umieszczany jest numer roku daty gregoriańskiej,
;	Mg - wskaźnik na zmienną, w której umieszczany jest numer miesiąca daty gregoriańskiej,
;	Dg - wskaźnik na zmienną, w której umieszczany jest numer dnia daty gregoriańskiej.
;
; Wartości zwracane:
;	* 0 dla prawidłowej daty juliańskiej,
;	* -1 w przeciwnym wypadku.
;
proc	JulianToGregorian, Yj, Mj, Dj, Yg, Mg, Dg

	.JulianToNum:
		stdcall DateToAbsDayNum, [Yj], [Mj], [Dj], 0
		test	eax, eax
		jz	.Error

	.NumToGregorian:
		stdcall AbsDayNumToDate, eax, 1, [Yg], [Mg], [Dg]
		jmp	.End

	.Error:
		mov	eax, -1

	.End:

	ret
endp


section '.edata' export data readable

	export	'Calendar.dll',\
		AbsDayNumToDate,	'AbsDayNumToDate',\
		DateToAbsDayNum,	'DateToAbsDayNum',\
		DayNumToMD,		'DayNumToMD',\
		DayOfWeek,		'DayOfWeek',\
		GregorianToJulian,	'GregorianToJulian',\
		IsLeapYear,		'IsLeapYear',\
		JulianToGregorian,	'JulianToGregorian',\
		MDToDayNum,		'MDToDayNum'


section '.reloc' fixups data discardable

© 2007-2014, Mikołaj Hajduk