
program Paschal { BP7, TP7, D3 DCC32 -cc } ;

{$I version.pas}
{$IFDEF WINDOWS} uses WinCrt ; {$ENDIF}
{$IFDEF DELPHI} uses Windows, SysUtils ; {$ENDIF}

const PID = 'PASCHAL.PAS - www.merlyn.demon.co.uk  >= 2008-01-30' ;


(* www.merlyn.demon.co.uk       1996-10-04 ff.     OK to FAQ.

  PeterDuffettSmith1() agrees with the 1996 IoP diary, PD-S's book p.5 2000,
  & samples from the Book of Common Prayer of the Church of England.

  PD-S is using an algorithm of 1876 from Butcher's Ecclesiastical Calendar,
  said to be valid from 1583 Gregorian onwards.

  PD-S and CT agree for all years in word; EGR & CDWF never disagreed, and
  now after range-acceptance modifications agree for all years in word.

  All agree with The Calendar FAQ for Easter 2001.

  The Gregorians agree among themselves, and with samples from diaries
  and the Book of Common Prayer ; the Julian/Dionysians lack much
  independent verification.

  Once the dates are known, a lookup table should generally be used.

  Visit  http://cssa.stanford.edu/~marcos/ec-cal.html  for more information.
  or follow links from my http://www.merlyn.demon.co.uk/index.htm

  To get the results of both DIV & MOD together, see MS in my remaindr.txt.

  I have not optimised all for speed, but retained resemblance to sources.

  Oct 2005 : Zeller's routines seem faster, try one here.

  Jan 2008 : adding jrsEaster, after estr-bcp.htm
  *)


(* Clive Feather, in http://www.davros.org/misc/easter.html 2000-05-25,
  Gregorian =>
  {}                        a := Yr mod 19 ;
  b := Yr div 100 ;         c := Yr mod 100 ;
  d := b div 4 ;            e := b mod 4 ;
  f := c div 4 ;            g := c mod 4 ;
  h := (8*b+13) div 25 ;
  {}                        j := (19*a+b-d-h+15) mod 30 ;
  m := (a+11*j) div 319 ;
  {}                        k := (2*e+2*f-g-j+m+32) mod 7 ;
  Mo := (j-m+k+90) div 25 ;
  {}                        Dy := (j-m+k+19+Mo) mod 32 ;

  That makes CDWF1; CDWF2 is deduced from that page (on 2000-06-09),
  with empirical weekday-phase adjustment.
  *)


(* See Peter Duffett-Smith (Downing College, Cambridge),
  Practical Astronomy with your Calculator, 2nd Ed, CUP 1981, p.4
  z.a := Y/19
  b.c := Y/100
  d.e := b/4
  f.z := (b + 8)/25
  g.z := (b - f + 1)/3
  z.h := (19*a + b - d - g + 15)/30
  i.k := c/4
  z.l := (32 + 2*e + 2*i - h - k)/7
  m.z := (a + 11*h + 22*l)/451
  n.p := (h + l - 7*m + 114)/31
  Month of Easter Sunday is now n (3=Mar, 4=Apr),
  and the day of the month is p+1.
  *)

(* The routine on p.80 of "The Calendar, David Ewing Duncan, Fourth
  Estate, 1999, ISBN 1-85702-979-8, and ascribed to "modern-day Catholic
  astronomers, is visibly the same. *)


(* Claus Tondering's "The Calendar FAQ", as at end 1998, contained :

  2.9.6. Isn't there a simpler way to calculate Easter?
  -----------------------------------------------------
  This is an attempt to boil down the information given in the previous
  sections (the divisions are integer divisions, in which remainders are
  discarded):
  G = year mod 19
  For the Julian calendar:
  I = (19*G + 15) mod 30
  J = (year + year/4 + I) mod 7
  For the Gregorian calendar:
  C = year/100
  H = (C - C/4 - (8*C+13)/25 + 19*G + 15) mod 30
  I = H - (H/28)*(1 - (H/28)*(29/(H + 1))*((21 - G)/11))
  J = (year + year/4 + I + 2 - C + C/4) mod 7
  Thereafter, for both calendars:
  L = I - J
  EasterMonth = 3 + (L + 40)/44
  EasterDay = L + 28 - 31*(EasterMonth/4)
  This algorithm is based in part on the algorithm of Oudin (1940) as
  quoted in "Explanatory Supplement to the Astronomical Almanac",
  P. Kenneth Seidelmann, editor.
  People who want to dig into the workings of this algorithm, may be
  interested to know that
  G is the Golden Number-1
  H is 23-Epact (modulo 30)
  I is the number of days from 21 March to the Paschal full moon
  J is the weekday for the Paschal full moon (0=Sunday, 1=Monday, etc.)
  L is the number of days from 21 March to the Sunday on or before
  the Paschal full moon (a number between -6 and 28)

  Nov 2001, FAQ version 2.4 omits the second (H/28)* in I, which is
  superfluous in principle.  However, as was, it prevents run-time error.
  I now have simplified, faster versions below, Gregorian & Julian; in
  those, L is changed.
  *)


(* The algorithms below are taken from Mapping Time by E.G.Richards,
  as given on his Web site.
  ----
  Algorithm N
  To calculate the 'day of March' of Easter Sunday for year Y according
  to the Dionysian canon (short form)
  1   A = MOD(Y,19)
  2   B = 22 + MOD(225 - 11*A,30)
  3   S = B + MOD(56 + 6*Y  - Y/4 - B,7)
  ----
  Algorithm P
  To calculate the 'day of March' of Easter Sunday for year Y according
  to the Gregorian canon (short form)
  1   A = Y/100
  2   B = A - A/4
  3   C = MOD(Y,19)
  4   D = MOD(15 + 19*C + B - (A - (A - 17)/25)/3,30)
  5   E = D - (C+11*D)/319
  6   S = 22 + E + MOD(140004 - Y - Y/4 + B - E,7)
  ----
  Algorithm Q
  To calculate day, D, and month, M (March=3, April=4) of Easter Sunday
  given the 'Day of March', S.
  1   M = 3 + S/32
  2   D = 1 + MOD(S-1,31)
  ----
  *)

(* The algorithm below is taken from my zel-incl.js and derives from
  Zeller's 1885 paper; it returns Day-Of-March.
  *)


type TYear = {$IFDEF PASCAL} word {$ENDIF} {$IFDEF DELPHI} cardinal {$ENDIF} ;
const Loops : word = 1 ;


procedure Empty(var Mo, Dy : byte ; const Yr {Greg.} : TYear) ;
var X : TYear ;
begin X := 3 ; Mo := X end {Empty} ;



(* See above *)
procedure ZEG1885(var Mo, Dy : byte ; const Yr {Greg.} : TYear) ;
var a, b, d, g, K, J, Ko4, Jo4, e : TYear ;
begin { Gregorian }
  K := Yr mod 100 ; J := Yr div 100 ;
  Ko4 := K div 4 ; Jo4 := J div 4 ; e := J mod 4 ;
  a := (K + 5*J) mod 19 ;
  g := J - Jo4 - (8*J+13) div 25  ;
  b := ( 19*a+15 + g ) mod 30 ;
  d := (b + K + Ko4 + 2 + 5*e) mod 7 ;
  if (d=0) and ( (b=29) or ((b=28) and (a>10)) ) then d := 7 ;
  Dy := 28 + b - d ;
  if Dy<32 then Mo := 3 else begin Mo := 4 ; Dec(Dy, 31) end ;
  end {ZEG1885} ;



(* See above *)
procedure PeterDuffettSmith1(var Mo, Dy : byte ; const Yr {Greg.} : TYear) ;
{} procedure proc(var u, v : TYear ; const P, Q : TYear) ;
{    Note - PDS would be much faster with proc inlined rather than called;
  and the MS trick would speed it too }
{} begin u := P div Q ; v := P mod Q end {proc} ;
var a, b, c, d, e, f, g, h, i, k, l, m, n, p, z : TYear ;
begin
  proc(z, a, Yr, 19) ;
  proc(b, c, Yr, 100) ;
  proc(d, e, b, 4) ;
  proc(f, z, (b + 8), 25) ;
  proc(g, z, (b - f + 1), 3) ;
  proc(z, h, (19*a + b - d - g + 15), 30) ;
  proc(i, k, c, 4) ;
  proc(z, l, (32 + 2*e + 2*i - h - k), 7) ;
  proc(m, z, (a + 11*h + 22*l), 451) ;
  proc(n, p, (h + l - 7*m + 114), 31) ;
  (* Month of Easter Sunday is now n (3=Mar, 4=Apr),
    and the day of the month is p+1 *)
  Mo := N ; Dy := Succ(P) end {PeterDuffettSmith1} ;


(* See above *)
procedure PeterDuffettSmith2(var Mo, Dy : byte ; const Yr {Greg.} : TYear) ;
{ Optimised from PDS1 by JRS }
var A, B, H, L, Z : TYear ;
begin
  A := Yr mod 19 ;
  B := Yr div 100 ;
  H := (19*A + B - (B shr 2) - (B - (B + 8) div 25 + 1) div 3 + 15) mod 30 ;
  L := (32 + 2*(B and 3) + 2*((Yr mod 100) div 4) - H - (Yr and 3)) mod 7 ;
  Z := H + L - 7*((A + 11*H + 22*L) div 451) + 114 ;
  Mo := 3 + Ord(Z>=31*4) ;
  Dy := Succ(Z mod 31) ;
  end {PeterDuffettSmith2} ;


(* See above *)
procedure ClausTondering1(var Mo, Dy : byte ; const Yr {Greg.} : TYear) ;
var g, c, h, i, j : TYear ; L : integer ;
begin { Gregorian }
  g := Yr mod 19 ;
  c := Yr div 100 ;
  h := (c - c div 4 - (8*c+13) div 25 + 19*g + 15) mod 30 ;
  i := h - (h div 28)*(1 - (h div 28)*(29 div (h+1))*((21-g) div 11)) ;
  j := (Yr mod 7 + Yr div 4 + i + 2 - c + c div 4) mod 7 ;
  L := integer(i) - integer(j) ;
  Mo := 3 + (L + 40) div 44 ;
  Dy := L + 28 - 31*(Mo div 4) ;
  end {ClausTondering1} ;


(* See above *)
procedure ClausTondering1a(var Mo, Dy : byte ; const Yr {Greg.} : TYear) ;
var g, c, i, j : TYear ; h: integer ; L : integer ;
begin { Gregorian }
  g := Yr mod 19 ;
  c := Yr div 100 ;
  h := (c - c div 4 - (8*c+13) div 25 + 19*g + 15) mod 30 ;
  i := h - (h div 28)*(1 - {(h div 28)*}(29 div (h+1))*((21-g) div 11)) ;
  j := (Yr mod 7 + Yr div 4 + i + 2 - c + c div 4) mod 7 ;
  L := integer(i) - integer(j) ;
  Mo := 3 + (L + 40) div 44 ;
  Dy := L + 28 - 31*(Mo div 4) ;
  end {ClausTondering1a} ;


(* See above *)
procedure TonderingRevised(var Mo, Dy : byte ; const Yr {Greg.} : TYear) ;
var g, c, h, i, j, L : TYear ;
begin { Gregorian }
  g := Yr mod 19 { 0..18 } ;
  c := Yr div 100 ;
  h := (c - c div 4 - (8*c+13) div 25 + 19*g + 15) mod 30 { 0..29 } ;

  (*  if h<28 then i := h
    else i := h - (1 - (29 div (h+1)) * ((21-g) div 11)) ;  *)

  (*  if h<28 then i := h
    else
    if h=28 then i := h - (1 - { (29 div (h+1)) * } ((21-g) div 11)   )
    else i := h - (1 { - (29 div (h+1)) *   ((21-g) div 11) } ) ; *)

  (*  if h<28 then i := h
    else
    if h=28 then i := h - (1 - ((21-g) div 11)   )
    else i := h - 1 ; *)

  (*  if h<28 then i := h
    else
    if h=28 then i := h - Ord(g>10) {(1 - ((21-g) div 11)   ) }
    else i := h - 1 ; *)

  if (h<28) or ((h=28) and (g<=10)) then i := h else i := h - 1 ;

  j := (Yr mod 7 + Yr div 4 + i + 2 - c + c div 4) mod 7 ;
  (*  L := integer(i) - integer(j) ;
    . Mo := 3 + (L + 12) div 44 ;
    . Dy := L - 31*(Mo div 4) ; *)
  L := (i+28) - j ;
  if L<=31 then begin Mo := 3 ; Dy := L    end
  {}       else begin Mo := 4 ; Dy := L-31 end ;
  end {TonderingRevised} ;


(* See above *)
procedure ClausTondering2(var Mo, Dy : byte ; const Yr {Juln.} : TYear) ;
var g, i, j : TYear ; L : integer ;
begin { Julian }
  g := Yr mod 19 ;
  i := (19*g + 15) mod 30 ;
  {  j := (Yr       + Yr div 4 + i) mod 7 ; }
  {} j := (Yr mod 7 + Yr div 4 + i) mod 7 { JRS mod } ;
  (*  L := integer(i) - integer(j) ;
    Mo := 3 + (L + 40) div 44 ;
    Dy := L + 28 - 31*(Mo div 4) ; *)
  L := (i+28) - j ;
  if L<=31 then begin Mo := 3 ; Dy := L    end
  {}       else begin Mo := 4 ; Dy := L-31 end ;
  end {ClausTondering2} ;


(* See above *)
procedure EGRichards1(var Mo, Dy : byte ; const Yr {Greg.} : TYear) ;
{ Algorithm P+Q : To calculate the 'day of March' of Easter Sunday
  for year Y according to the Gregorian canon (short form) }
var A, B, C, D, E, S : TYear ;
begin { Tested ok *after* 1699 ; now OK 0..65535 }
  A := Yr div 100 ;
  B := A - A div 4 ;
  C := Yr mod 19 ;
  {  D := (15 + 19*C + B - (A     - (A-17) div 25) div 3) mod 30 ; }
  {} D := (15 + 19*C + B - (A + 1 - (A+ 8) div 25) div 3) mod 30 { JRS mod } ;
  E := D - (C+11*D) div 319 ;
  S := 22 + E + (140004 - Yr - Yr div 4 + B - E) mod 7 ;
  Mo := 3 + S div 32 ;
  Dy := 1 + (S-1) mod 31 ;
  end {EGRichards1} ;


(* See above *)
procedure EGRichards3(var Mo, Dy : byte ; const Yr {Juln.} : TYear) ;
{ Algorithm N+Q : To calculate the 'day of March' of Easter Sunday
  for year Y according to the Dionysian canon (short form) }
var A, B, S : TYear ;
begin { seemed OK *up*to* 10912 ; now seems OK 0..65535 }
  A := Yr mod 19 ;
  B := 22 + (225-11*A) mod 30 ;
  {  S := B + (56 + 6* Yr        -  Yr div 4        - B) mod 7 ; }
  {} S := B + (56 + 6*(Yr mod 7) - (Yr div 4) mod 7 - B) mod 7 { JRS mod } ;
  Mo := 3 + S div 32 ;
  Dy := 1 + (S-1) mod 31 ;
  end {EGRichards3} ;


(* See above *)
procedure CDWF1(var Mo, Dy : byte ; const Yr {Greg.} : TYear) ;
var a, b, c, d, e, f, g, h, j, k, m : TYear ;
begin { Tested ok *after* ???? ; now OK ???? }
  {}                        a := Yr mod 19 ;
  b := Yr div 100 ;         c := Yr mod 100 ;
  d := b div 4 ;            e := b mod 4 ;
  f := c div 4 ;            g := c mod 4 ;
  h := (8*b+13) div 25 ;
  {}                        j := (19*a+b-d-h+15) mod 30 ;
  m := (a+11*j) div 319 ;
  {}                        k := (32+2*e+2*f-g-j+m) mod 7 {reordered} ;
  Mo := (j-m+k+90) div 25 ;
  {}                        Dy := (j-m+k+19+Mo) mod 32 ;
  end {CDWF1} ;


(* See above *)
procedure CDWF2(var Mo, Dy : byte ; const Yr {Juln.} : TYear) ;
const KK = 0 { empirical } ;
FullMoon : array [1..19] of byte { day of March } =
  (36,25,44,33,22,41,30, 49,38,27,46,35,24, 43,32,21,40,29,48) ;
var GoldNo, PaschFM, DoWk : TYear ;
begin { Tested ok }
  GoldNo := Succ(Yr mod 19) ;
  PaschFM := FullMoon[GoldNo] ;
  DoWk := ((Yr mod 7) + (Yr div 4) + PaschFM + KK) mod 7 ;
  Mo := 3 ;
  Dy := PaschFM + 7 - DoWk ;
  if Dy>31 then begin Dec(Dy, 31) ; Inc(Mo) end ;
  end {CDWF2} ;







(* Found in  http://www.gnomehome.demon.nl/uddf/pages/dates.htm#dates1

  function TtheCalendar.CalcEaster:String;
  var B,D,E,Q:Integer;
  GF:String;
  begin
  B:=225-11*(Year Mod 19);
  D:=((B-21)Mod 30)+21;
  If D>48 then Dec(D);
  E:=(Year+(Year Div 4)+D+1)Mod 7;
  Q:=D+7-E;
  If Q<32 then begin
  If ShortDateFormat[1]='d' then
  Result:=IntToStr(Q)+'/3/'+IntToStr(Year)
  else Result:='3/'+IntToStr(Q)+'/'+IntToStr(Year);
  end
  else begin
  If ShortDateFormat[1]='d' then
  Result:=IntToStr(Q-31)+'/4/'+IntToStr(Year)
  else Result:='4/'+IntToStr(Q-31)+'/'+IntToStr(Year);
  end;
  {calc good friday}
  If Q<32 then begin
  If ShortDateFormat[1]='d' then  GF:=IntToStr(Q-2)+'/3/'+IntToStr(Year)
  else GF:='3/'+IntToStr(Q-2)+'/'+IntToStr(Year);
  end
  else begin
  If ShortDateFormat[1]='d' then
  GF:=IntToStr(Q-31-2)+'/4/'+IntToStr(Year)
  else GF:='4/'+IntToStr(Q-31-2)+'/'+IntToStr(Year);
  end;

  end;
  *)


(* Converted to BP7 *)
procedure UDDF(var Mo, Dy : byte ; const Year {Greg., 1900..2099} : TYear) ;
var B, D, E, Q : longint ;
begin
  B := 225-11*(Year mod 19) ;
  D := ((B-21) mod 30)+21 ;
  if D>48 then Dec(D) ;
  E := (longint(Year)+(Year div 4)+D+1) mod 7 ;
  Q := D+7-E ;
  if Q<32 then
    begin Mo := 3 ; Dy := Q end else
    begin Mo := 4 ; Dy := Q-31 end ;
  end {UDDF} ;




{$IFDEF DELPHI}
type NearYear = 1900..2099 (* CARE *) ;
function NearEaster(const Year : NearYear) : TDateTime ;
{ Origin unknown; quoted by AGL; tested by JRS; modified }
var B, D, E, Q : integer ;
begin
  B := 225 - (11 * (Year mod 19)) ;
  D := ((B - 21) mod 30) + 21 ;
  if D > 48 then dec(D);
  E := (Year + (Year div 4) + D + 1) mod 7 ;
  Q := D + 6 - E ;
  Result := EncodeDate(Year, 3, 1) + Q ;
  end {NearEaster} ;
{$ENDIF}





{$IFDEF DELPHI ???}

(* Good JavaScript from estr-bcp.htm :
function DoMtoMMM_dD(DM) { // DayOfMarch to M D
  return (DM<32 ? "Mar" : "Apr") + SpcsTo(1 + (DM-1)%31, 3) }

function jrsEaster(YR) { // Fast JRSEaster, unsigned 32-bit year
  var gn, xx, cy, DM
  gn = YR % 19					// gn ~ GoldenNumber
  xx = (YR/100)|0
  cy = ((3*(xx+1)/4)|0) - (((13+xx*8)/25)|0)	// cy ~ BCPcypher
  xx = ( 6 + YR + ((YR/4)|0) - xx + ((YR/400)|0) ) % 7
  DM = 21 + (gn*19 + cy + 15)%30 ; DM -= ((gn>10) + DM > 49) // PFM
  return DM + 1 + (66-xx-DM)%7 /* Day-of-March */ }
*)

(* Tested for a FEW YEARS only *)

function jrsEaster(const YR : integer) : integer ;
  (* Fast JRSEaster, unsigned 32-bit year - Delphi/Pascal ?
     TRACEABLE via estr-bcp.htm (qv) to Prayer Book & Calendar Act *)
var gn, xx, cy, DM : integer ;
begin
  gn := YR mod 19 ;				{ gn ~ GoldenNumber }
  xx := YR div 100 ;
  cy := 3*(xx+1) div 4 - (13+xx*8) div 25 ;	{ cy ~ BCPcypher }
  xx := ( 6 + YR + YR div 4 - xx + YR div 400 ) mod  7 ;
  DM := 21 + (gn*19 + cy + 15) mod 30 ;
  Dec(DM, Ord( Ord(gn>10) + DM > 49 )) ;	{ PFM }
  jrsEaster := DM + 1 + (66-xx-DM) mod 7 ;	{ Day-of-March }
  end {jrsEaster} ;

function DoMtoMMM_dD(const DM : integer) : string ; { DayOfMarch to M D }
const MA : array [boolean] of string [3] = ('Mar', 'Apr') ;
begin
  (* Pascal : var S : string [3] ; Str(1 + (DM-1) mod 31 : 3, S) ;
     DoMtoMMM_dD := MA[DM>31] + S ; *)
  DoMtoMMM_dD := Format('%s %2d', [MA[DM>31], 1 + (DM-1) mod 31]) ;
  end {DoMtoMMM_dD} ;

procedure myEaster(var Mo, Dy : byte ; const Yr {Greg.} : TYear) ;
  (* Fast JRSEaster, unsigned 32-bit year - Delphi/Pascal ?
     TRACEABLE via estr-bcp.htm (qv) to Prayer Book & Calendar Act *)
var gn, xx, cy, DM : integer ;
begin
  gn := YR mod 19 ;				{ gn ~ GoldenNumber }
  xx := YR div 100 ;
  cy := 3*(xx+1) div 4 - (13+xx*8) div 25 ;	{ cy ~ BCPcypher }
  xx := ( 6 + YR + YR div 4 - xx + YR div 400 ) mod  7 ;
  DM := 21 + (gn*19 + cy + 15) mod 30 ;
  Dec(DM, Ord( Ord(gn>10) + DM > 49 )) ;	{ PFM }
  Dy := DM + 1 + (66-xx-DM) mod 7 ;	{ Day-of-March }
  Mo := 3 + Ord(Dy>31) ; if Dy>31 then Dec(Dy, 31) ;
  end {myEaster} ;

{$ENDIF}





(*
  function Tix : longint ; assembler ;
  asm  mov ah,0 ; int $1a { Get $40:$6C 18.2Hz clock - not midnight-safe } ;
  {$IFDEF PASCAL} mov ax,dx ; mov dx,cx ; {$ENDIF}
  {$IFDEF DELPHI} mov ax,cx ; shl eax,16 ; mov ax,dx ; {$ENDIF}
  end {Tix} ;
  *)

function Timer : longint { P: 55ms; D: 1ms } ;
{$IFDEF PASCAL} assembler ; {$ENDIF}
{$IFDEF BORPAS}
asm
    mov es,[Seg0040] ;
  @1: mov ax,[es:$6c] ; mov dx,[es:$6e] ; mov cl,[es:$70]
    cmp ax,[es:$6c] ; jne @1
    cmp cl,0 ; je @2
    add ax,$B0 ; adc dx,$18 ;
  @2:
    end {$ENDIF}
{$IFDEF __TMT__} asm  mov eax,[$046C]  end {$ENDIF}
{$IFDEF DELPHI} begin Timer := GetTickCount end {$ENDIF}
{Timer} ;


procedure Wr(const ID : string ; const Y : TYear ; const Cal : string ;
  const M, D : byte) ;
begin Writeln(' (', ID:4, ':) In AD ', Y, ', ', Cal:9,
    ' Easter Sunday = Month ', M, ' Day ', D) end {Wr} ;


procedure SomeYear(const Year : TYear) ;
var Month, Day : byte ; {$IFDEF DELPHI} Y, M, D : word ; {$ENDIF}
begin
  ZEG1885(Month, Day, Year) ;
  Wr('ZEG5 ', Year, 'Gregorian', Month, Day) ;
  PeterDuffettSmith1(Month, Day, Year) ;
  Wr('PDS1 ', Year, 'Gregorian', Month, Day) ;
  PeterDuffettSmith2(Month, Day, Year) ;
  Wr('PDS2 ', Year, 'Gregorian', Month, Day) ;
  ClausTondering1(Month, Day, Year) ;
  Wr('CT1  ', Year, 'Gregorian', Month, Day) ;
  ClausTondering1a(Month, Day, Year) ;
  Wr('CT1a ', Year, 'Gregorian', Month, Day) ;
  TonderingRevised(Month, Day, Year) ;
  Wr('CTrev', Year, 'Gregorian', Month, Day) ;
  EGRichards1(Month, Day, Year) ;
  Wr('EGR1 ', Year, 'Gregorian', Month, Day) ;
  CDWF1(Month, Day, Year) ;
  Wr('CDWF1', Year, 'Gregorian', Month, Day) ;
  if (Year>=1900) and (Year<=2099) then begin
    UDDF(Month, Day, Year) ;
    Wr('UDDF ', Year, 'Gregorian', Month, Day) end ;
  {$IFDEF DELPHI}
  if (Year>=1900) and (Year<=2099) then begin
    DecodeDate(NearEaster(Year), Y, M, D) ;
    Wr('NearE', Year, 'Gregorian', M, D) end ;
  myEaster(Month, Day, Year) ;
  Wr('myE  ', Year, 'Gregorian', Month, Day) ;
  {$ENDIF}
  Writeln ;
  ClausTondering2(Month, Day, Year) ;
  Wr('CT2  ', Year, 'Julian', Month, Day) ;
  EGRichards3(Month, Day, Year) ;
  Wr('EGR3 ', Year, 'Dionysian', Month, Day) ;
  CDWF2(Month, Day, Year) ;
  Wr('CDWF2', Year, 'Julian', Month, Day) ;
  end {SomeYear} ;


procedure Consistency ;
var Y : TYear ; Month, Day, M, D : byte ;
{$IFDEF DELPHI} YY, MM, DD : word ; {$ENDIF}
begin
  Writeln('   65536 years : consistency check,',
    ' then each routine is timed in ',
    {$IFDEF PASCAL} '55', {$ENDIF}
    {$IFDEF DELPHI} '1', {$ENDIF}
    'ms units :') ;
  for Y := 0 to 65535 do begin
    Write(^M, Y:5, #32) ;
    PeterDuffettSmith1(Month, Day, Y) ;
    (* if Y>=532 then begin
      PeterDuffettSmith1(M, D, Y-532)  { not matching } ;
      if (Month<>M) or (Day<>D) then Writeln(' K') ;
      end ; *)
    PeterDuffettSmith2(M, D, Y) ;
    if (Month<>M) or (Day<>D) then Writeln(' w') ;
    ZEG1885(M, D, Y) ;
    if (Month<>M) or (Day<>D) then Writeln(' z') ;
    ClausTondering1(M, D, Y) ;
    if (Month<>M) or (Day<>D) then Writeln(' x') ;
    ClausTondering1a(M, D, Y) ;
    if (Month<>M) or (Day<>D) then Writeln(' t') ;
    TonderingRevised(M, D, Y) ;
    if (Month<>M) or (Day<>D) then Writeln(' u') ;
    EGRichards1(M, D, Y) ;
    if (Month<>M) or (Day<>D) then Writeln(' y') ;
    CDWF1(M, D, Y) ;
    if (Month<>M) or (Day<>D) then Writeln(' f') ;

    if (Y>=1900) and (Y<=2099) then begin
      UDDF(M, D, Y) ;
      if (Month<>M) or (Day<>D) then Writeln(' u') ;
      end ;

    {$IFDEF DELPHI}
    if (Y>=1900) and (Y<=2099) then begin
      DecodeDate(NearEaster(Y), YY, MM, DD) ;
      if (Month<>MM) or (Day<>DD) then Writeln(' n') ;
      end ;
    MyEaster(M, D, Y) ;
    if (Month<>M) or (Day<>D) then Writeln(' J') ;
    {$ENDIF}

    ClausTondering2(Month, Day, Y) ;
    if Y>=532 then begin { check repeat }
      ClausTondering2(M, D, Y-532) ;
      if (Month<>M) or (Day<>D) then Writeln(' Q') ;
      end ;

    EGRichards3(M, D, Y) ;
    if (Month<>M) or (Day<>D) then Writeln(' z') ;
    CDWF2(M, D, Y) ;
    if (Month<>M) or (Day<>D) then Writeln(' g') ;
    end { Test all years } ;
  Writeln ;
  end {Consistency} ;


procedure Timing ;
var T : longint ; Y : TYear ; Q : word ; Month, Day : byte ;
{$IFDEF DELPHI} DT : TDateTime ; {$ENDIF}
begin

  Writeln('  Calibrating :') ;
  repeat
    T := Timer ;
    for Q := 1 to Loops do
      for Y := 0 to 65535 do Empty(Month, Day, Y) ;
    T := Timer-T ;
    Write(' ', T) ;
    if T>4 {$IFDEF DELPHI} *15 {$ENDIF} then BREAK ;
    Loops := Loops + 1 + Loops div 5 until false ;
  Writeln ;
  Writeln ;

  Writeln('  Times : Call :') ;
  T := Timer ;
  for Q := 1 to Loops do
    for Y := 0 to 65535 do Empty(Month, Day, Y) ;
  Writeln('   Empty ', Timer-T:5) ;
  Writeln ;

  Writeln('  Times : Greg :') ;
  T := Timer ;
  for Q := 1 to Loops do
    for Y := 0 to 65535 do PeterDuffettSmith2(Month, Day, Y) ;
  Writeln('   PDS2  ', Timer-T:5) ;
  T := Timer ;
  for Q := 1 to Loops do
    for Y := 0 to 65535 do ZEG1885(Month, Day, Y) ;
  Writeln('   ZEG5  ', Timer-T:5) ;
  T := Timer ;
  for Q := 1 to Loops do
    for Y := 0 to 65535 do CDWF1(Month, Day, Y) ;
  Writeln('   CDWF1 ', Timer-T:5) ;
  T := Timer ;
  for Q := 1 to Loops do
    for Y := 0 to 65535 do ClausTondering1(Month, Day, Y) ;
  Writeln('   CT1   ', Timer-T:5) ;
  T := Timer ;
  for Q := 1 to Loops do
    for Y := 0 to 65535 do ClausTondering1a(Month, Day, Y) ;
  Writeln('   CT1a  ', Timer-T:5) ;
  T := Timer ;
  for Q := 1 to Loops do
    for Y := 0 to 65535 do TonderingRevised(Month, Day, Y) ;
  Writeln('   CTrev ', Timer-T:5) ;
  T := Timer ;
  for Q := 1 to Loops do
    for Y := 0 to 65535 do EGRichards1(Month, Day, Y) ;
  Writeln('   EGR1  ', Timer-T:5) ;
  T := Timer ;
  for Q := 1 to Loops do
    for Y := 0 to 65535 do PeterDuffettSmith1(Month, Day, Y) ;
  Writeln('   PDS1  ', Timer-T:5) ;
  T := Timer ;
  for Q := 1 to Loops do
    for Y := 0 to 65535 do UDDF(Month, Day, Y) ;
  Writeln('   UDDF  ', Timer-T:5) ;

  {$IFDEF DELPHI}
  DT := 1 ;
  T := Timer ; 
  for Q := 1 to Loops do
    for Y := 0 to 65535 do DT := NearEaster(1900 + Y mod 200) ;
  Writeln('   NearE ', Timer-T:5) ;
  T := Timer ;
  for Q := 1 to Loops do
    for Y := 0 to 65535 do myEaster(Month, Day, Y) ;
  Writeln('   Mine  ', Timer-T:5) ;
  if DT=0 then Writeln ;
  {$ENDIF}

  Writeln ;
  Writeln('  Times : Juln :') ;
  T := Timer ;
  for Q := 1 to Loops do
    for Y := 0 to 65535 do CDWF2(Month, Day, Y) ;
  Writeln('   CDWF2 ', Timer-T:5) ;
  T := Timer ;
  for Q := 1 to Loops do
    for Y := 0 to 65535 do ClausTondering2(Month, Day, Y) ;
  Writeln('   CT2   ', Timer-T:5) ;
  T := Timer ;
  for Q := 1 to Loops do
    for Y := 0 to 65535 do EGRichards3(Month, Day, Y) ;
  Writeln('   EGR3  ', Timer-T:5) ;
  Writeln ;
  end {Timing} ;


var Year, X : TYear ;

BEGIN Writeln(PID) ;
repeat
  Write('Year (>0) ? ') ; Readln(Year) ;

  if Year=0 then begin
    Write('   0=QUIT / 1=Autotest / 2=back ? ') ; Readln(X) ;

    case X of
      0 :  BREAK ;
      1 : begin Consistency ; Timing end ;
      end {case} ;

    CONTINUE ;
    end {Year=0} ;

  SomeYear(Year) ;

  until false ;

Writeln('Done.') ;

END.
