dandelion said:
I'd just create a table holding the days_in_month. Something like
.... snip ...
Then, you need 'leapyear' info for February, which isn't that
hard to calculate. IIRC it's a leapyear if year % 4 == 0 &&
year % 100 != 0.
Here is a routine I used to use to compute yr, mo, day from the
CP/M date stamp, which corresponded to days since 1 Jan 1978. To
use it you need to make a preliminary conversion of seconds since
something into days since something. Dealing with quad years of
1461 days avoids a plethora of silly errors. No need to worry
further about leap year until 2100.
PROCEDURE drtodate(thedate : integer; VAR yr, mo, day : integer);
(* 1 Jan 1978 corresponds to Digital Research date = 1 *)
(* BUG - cannot handle negative values for dates > 2067 *)
VAR
i, y1 : integer;
dayspermonth : ARRAY[1..12] OF 1..31;
BEGIN (* drtodate *)
FOR i := 1 TO 12 DO dayspermonth
:= 31;
dayspermonth[4] := 30; dayspermonth[6] := 30;
dayspermonth[9] := 30; dayspermonth[11] := 30;
IF thedate > 731 THEN BEGIN (* avoid overflows *)
yr := 1980; thedate := thedate - 731; END
ELSE BEGIN
thedate := thedate + 730; yr := 1976; END;
(* 0..365=y0; 366..730=y1; 731..1095=y2; 1096..1460=y3 *)
i := thedate DIV 1461; thedate := thedate MOD 1461;
y1 := (thedate-1) DIV 365; yr := yr + y1 + 4*i;
IF y1 = 0 THEN (* leap year *) dayspermonth[2] := 29
ELSE BEGIN
thedate := thedate - 1; (* 366 -> 365 -> 1 Jan *)
dayspermonth[2] := 28; END;
day := thedate - 365*y1 + 1; mo := 1;
WHILE day > dayspermonth[mo] DO BEGIN
day := day - dayspermonth[mo];
mo := succ(mo); END;
END; (* drtodate *)