[comp.lang.prolog] Need calendar arithmetic code

bcs@PRC.Unisys.COM (Barry Silk) (02/07/91)

Could anyone out there in netland please help me out?  I'm looking for
prolog routines that can do calendar arithmetic.  That is, I need
routines that can add/subtract an arbitrary number of days to a given
date to produce a resultant date.

If the calendar arithmetic routines are not available, a routine to 
convert dates to/from julian dates would be just as useful.

Thanks in advance!!

--Barry

-----------------------------------------------------------------------
Barry Silk				             bcs@prc.unisys.com
Unisys - Center for Advanced Information Technology  (215) 648-2509
-----------------------------------------------------------------------

lee@munnari.oz.au (Lee Naish) (02/07/91)

In article <16382@burdvax.PRC.Unisys.COM> bcs@PRC.Unisys.COM (Barry Silk) writes:
>Could anyone out there in netland please help me out?  I'm looking for
>prolog routines that can do calendar arithmetic.

I have some NU-Prolog code which might be useful to you.  It needs
modification for standard Prolog.  Dates are represented as strings
(eg, "31/12/1991") or structures (eg, date(1991, 12, 31)) more efficient 
for manipulation/comparison.  The code was written with logic and
simplicity in mind, rather than efficiency.

	lee

	% utilities for handling dates and times
	% (may change db format for these some time)

	% subtract a certain number of days from a date
	% to get a previous date
date_minus(Date, ND, PDate) :-
	date_to_triple(Date, TDate),
	tdate_minus(TDate, ND, TPDate),
	date_to_triple(PDate, TPDate).

	% as above for dates in date(yr, mo, dd) format
tdate_minus(date(Y, M, D), ND, date(PY, PM, PD)) :-
	(if ND < D then		% prev day in same month
		PY = Y,	
		PM = M,
		PD is D - ND
	else if M > 1 then	% prev month, same year
		M1 is M - 1,
		month(M1, _, Y, D1),
		ND1 is ND - D,
		tdate_minus(date(Y, M1, D1), ND1, date(PY, PM, PD))
	else			% prev year
		Y1 is Y - 1,
		M1 is 12,
		month(M1, _, Y1, D1),
		ND1 is ND - D,
		tdate_minus(date(Y1, M1, D1), ND1, date(PY, PM, PD))
	).

	% month numbers, names, year and number of days
month(1, "Jan", _, 31).
month(2, "Feb", Y, D) :-
	(if Y mod 4 =:= 0 /* , Y mod 100 =\= 0 */ then	% fix!
		D = 29
	else
		D = 28
	).
month(3, "Mar", _, 31).
month(4, "Apr", _, 30).
month(5, "May", _, 31).
month(6, "Jun", _, 30).
month(7, "Jul", _, 31).
month(8, "Aug", _, 31).
month(9, "Sep", _, 30).
month(10, "Oct", _, 31).
month(11, "Nov", _, 30).
month(12, "Dec", _, 31).

	% convert from/to string date to/from date/3 format
	% works in both directions (using coroutines)
date_to_triple(Date, date(Y, M, D)) :-
	append(DS, 0'/.MYS, Date),
	append(MS, 0'/.YS, MYS),
	intToString(Y, YS),
	intToString(M, MS),
	intToString(D, DS).

	% compare dates
date_compare(Date1, Date2, R) :-
	date_to_triple(Date1, T1),
	date_to_triple(Date2, T2),
	termCompare(R, T1, T2).

	% >= for dates
date_ge(Date1, Date2) :-
	date_compare(Date1, Date2, R),
	R ~= (<).