Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!mailrus!purdue!tut.cis.ohio-state.edu!thurn
From: thurn@cis.ohio-state.edu (Martin 'Sulu' Thurn)
Newsgroups: comp.lang.pascal
Subject: Re: day-of-week algorithm
Message-ID: <59529@tut.cis.ohio-state.edu>
Date: 1 Sep 89 17:32:50 GMT
Sender: thurn@tut.cis.ohio-state.edu
Lines: 86

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!