[comp.lang.pascal] day-of-week algorithm

natec@infohh.rmi.de (NATEC Institut GmbH) (04/12/89)

try this approximation:

Function DayOfWeek ( Day, Month : Byte; Year : Word ) : Byte;
Function Leap : Byte; begin if Month>2 then Leap:=8 else Leap:=0 end;
begin
  DayOfWeek:= Trunc(Day+1+Int(Month/0.39)+(Year+Leap)/4+Int(Year*0.99)+
      Int(Year/400)) mod 7;
end;

- and, by the way, this is Easter:

Function Easter ( Year : Word ) : String;  { GAUSSIAN }
var d,e,f,M,N : Byte;
    a,s       : String;
begin
  if (Year<1700) or (Year>2199) then Easter:= 'don''t know' else begin
    Str (Year,a);
    M:= 24;
    if Year<1900 then M:= 23;
    N:= Trunc(Year/100) - 14;
    if N = 7 then N:= 6;
    d:= (19*(Year mod 19)+M) mod 30;
    e:= ( 2*(Year mod  4)+4*(Year mod 7)+6*d+N) mod 7;
    if 22+d+e < 32 then begin
      Str(22+d+e,s);
      Easter:= s+'.Mar.'+a
    end else begin
      f:= d+e-9;
      if  f = 26 then  f:= 19;
      if (f = 25) and (d = 28) and (Year mod 19 > 10) then f:= 18;
      Str (f,s);
      Easter:= s+'.Apr.'+a
    end
  end
end;

Dr Gerd C Schmerse  |  natec@infohh.rmi.de     |     ___    
NATEC Institut      |  49 40 88300170 (fax)    |    /o o\   
Hamburg, W.Germany  |  49 40 88300124 (voice)  | -m-"-U-"-m-

thurn@cis.ohio-state.edu (Martin 'Sulu' Thurn) (09/02/89)

I apologize if this has already been discussed, but I recently discovered
a point of confusion / error (gasp!) in the day-of-week algorithm posted
here several months ago.
This article appeared last April (1989):

>Article 1563 of comp.lang.pascal:
>From: RDK%vm.temple.edu@cunyvm.cuny.edu (Robert Keiser)
>
>I have used the following algorithm to get the Day of week.  It will work for
>any date after 1800.  In the following, Year is a 4 digit integer i.e. 1989
>not just the 89 part.
>
>     N := 1461*f(year,month) / 4 + 153*g(month) / 5 + day
>
> where:
>          f(year,month) = year - 1         if month <= 2
>                          year             otherwise
>
>          g(month)      = month + 13       if month <= 2
>                          month + 1        otherwise
>
> Then apply the following formula to N
>     dow = (N - 621,049) MOD 7
>
> This formula was found in _Programming in ANSI C_
> by Stephen G. Kochan pg. 188
>
>Robert Keiser
>Bitnet   : RDK@Templevm
>Internet : RDK@vm.temple.edu

  (* the above formula returns  0 for saturday,
                                1 for sunday,
                                ...
                                6 for friday.       *)

Without giving it much thought, (i.e. what the heck do these numbers mean?),
I implemented (and modified) this in TurboPascal 5.0 as follows:

function  day_of_week(y,m,d:word): day;
  const
    f:array[monthrange] of integer=(-1,-1,0,0,0,0,0,0, 0, 0, 0, 0);
    g:array[monthrange] of byte=   (14,15,4,5,6,7,8,9,10,11,12,13);
  var
    tempint:longint;
  begin
{   tempint := round( ((1461*(y+f[m])) / 4) +
                      ((153 *   g[m])  / 5) + d - 621049 ) MOD 7;
     ^^^^ my first attempt,
          gives trouble when (153*month) MOD 5 > 2   e.g. 1 sep 1989    }

{   tempint := ceiling( ((1461*(y+f[m])) / 4) +
                      ((153 *   g[m])  / 5) + d - 621049 ) MOD 7;
     ^^^^ my second attempt,
          gives trouble when (153*month) MOD 5 = 4   e.g. 1 dec 1989    }

    tempint := ( ceiling(  (1461*(y+f[m])) / 4 + 0.01) +
                 trunc((153 *   g[m])  / 5) + d - 621049 ) MOD 7;
{    ^^^^ this one is perfect! (?)   }

    if  (tempint = 0)  then
      tempint := 7;  (* so sunday = 1, ... saturday = 7  *)
    day_of_week := day(tempint);
  end;


So, notice that a correct (unless I missed something) version of this 
algorithm requires rounding up the year calculation (adding 1 if it comes out
with no fractional part) and throwing out the fractional part of the month 
calculation.  I don't know why this works, but it is based on an empirical
test (and successfully finding calendars of 4 different years) of all 
20 combinations of how the fractional parts of the year and
month calculations turn out.  If anyone is interested, I can e-mail my
Quattro spreadsheet :-O
  On another note (which I didn't think about until after I had done all 
the dirty work), what the heck is this 621049 business?  We're immediately 
taking MOD 7, so why not just subtract (621049 MOD 7) and be done with it?
  On anothother note: That year calculation turns out to be y * 365.25,
which "makes sense" because every 4th year is a leap year.  But what about
every 400th year is NOT a leap year?  Should there be a factor of /400ths
in there somewhere?  My mind is a bit too boggled at the moment, but I 
figure I have 10 years to figure it out.

---Martin Thurn    thurn@cis.ohio-state.edu     73747.224@compuserve.com

Disclaimer: The preceding statements are n...Wait a minute! I AM the company!

RDK%vm.temple.edu@cunyvm.cuny.edu (Robert Keiser) (09/02/89)

On 1 Sep 89 17:32:50 GMT you said:
>I apologize if this has already been discussed, but I recently discovered
>a point of confusion / error (gasp!) in the day-of-week algorithm posted
>here several months ago.
>This article appeared last April (1989):
>
 ...omitted original message...
>  (* the above formula returns  0 for saturday,
>                                1 for sunday,
>                                ...
>                                6 for friday.       *)
>
This is interesting,  When I run it on a Cyber it comes out with the following
results:
                0 = Sunday
                1 = Monday
                ...
                6 = Saturday

I think that I just found the problem.  I apologize for my original posting.
The original algorithm was from a C book so no DIV function.  The text that
accompanied the algorithm clarified things.  The function should look like
this.

 N := ((1461 * F(Year,Month)) DIV 4) + ((153 * G(Month)) DIV 5) + Day;
 DOW := (N - 621049) MOD 7;

When I wrote to the list I just pulled the comments but didn't look at the
code that I wrote to go along with it.
 ... Rest of letter deleted. ...
>
>---Martin Thurn    thurn@cis.ohio-state.edu     73747.224@compuserve.com
>
>Disclaimer: The preceding statements are n...Wait a minute! I AM the company!

I'm suprised it took this long to show up.

Robert Keiser
Systems Analyst
Temple University Computer Activities

Bitnet     : RDK@Templevm
Internet   : RDK@vm.temple.edu
CompuServe : 73607.1047@Compuserve.com
US Mail    : Temple University
             Philadelphia, PA 19122

evan@unix.cis.pitt.edu (Evan Ron Aussenberg) (09/03/89)

In article <59529@tut.cis.ohio-state.edu> thurn@cis.ohio-state.edu (Martin 'Sulu' Thurn) writes:
[..stuff about a day of week calc..]
>  On anothother note: That year calculation turns out to be y * 365.25,
>which "makes sense" because every 4th year is a leap year.  But what about
>every 400th year is NOT a leap year?  Should there be a factor of /400ths
>in there somewhere?  My mind is a bit too boggled at the moment, but I 
>figure I have 10 years to figure it out.

I knew somewhere, I had once heard that every XXXyears the leap year is skipped.
I never could remember where I read it, and no one I told thought I was
serious.  Now, what about my other recollection that every XXXyears there
is something when we have to skip a -whole- month or something wierd like
that?  (Sorry, this isn't much about pascal)

>---Martin Thurn    thurn@cis.ohio-state.edu     73747.224@compuserve.com
>
>Disclaimer: The preceding statements are n...Wait a minute! I AM the company!


Evan

             ____________________________________________________
            /                                                    \
           /     evan@unix.cis.pitt.edu / evan@Pittvms.BITNET     \
          /________________________________________________________\