[comp.lang.pascal] Day-of-week algorithm, please!

HE891C%GWUVM.BITNET@cunyvm.cuny.edu (The Time Traveler) (04/08/89)

I know this isn't quite appropriate to the list, but I really need an
algorithm that will return the day of the week given today's date.
Thanx in advance.

azarian@hpcc01.HP.COM (Randy Azarian) (04/10/89)

FUNCTION calcnumdays (month,day,year : integer) : word;

(* this function calculates the total number of days elapsed between 
   parameters passed , month, day, and year, and january 1, 1901.  this
   function is used to the day of the week, by knowing that january 1,
   1901 was a tuesday.  modulus division can then determine the day of
   the week by calculating something to the effect as follows:

   IF THE TOTAL NUMBER OF DAYS MODULUS 7 EQQUALS 0 THEN IT IS A TUESDAY.

   the rest of the days of the week can be calculated relative to the above
   statement.

*)

(* daysinmonth is a function you can write yourself that returns,
   obviously, the number of days in the month.
   i.e   x := daysinmonth(2,88);  x is set to 29

   if the month is not february, then year can be anything
*)

var monthctr, total : integer;

begin
  total := day -1;
  for monthctr := 1 to month-1 do
    total := total + daysinmonth(monthctr,year);

  total := total + 365 * (year - 1);
  total := total + + (year - 1) div 4;
  calcnumdays := total;
end;

nate@neutron.lcs.mit.edu (04/10/89)

To time traveler,

convert date to julian date and then do integer divide by 7.

see pd1:<msdos.turbopas>postscript.cvt  in simtel20 archives
for such a routine.

good luck

nate liskov

RDK%vm.temple.edu@cunyvm.cuny.edu (Robert Keiser) (04/11/89)

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
Systems Analyst
Temple University Computer Activities

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

cs3b3aj@maccs.McMaster.CA (Stephen M. Dunn) (04/11/89)

In article <1780001@hpcc01.HP.COM> azarian@hpcc01.HP.COM (Randy Azarian) writes:
...
>  total := total + + (year - 1) div 4;

   But watch out, because not every year such that year mod 4 = 0 is a leap
year!  The strangeness in the pattern occurs on century years, but I'm not 
sure which way round it is.  It is either that years divisible by 400 are
_not_ leap years, or that any century year is not a leap year _except_
for years divisible by 400.

   Confused?  It's either that 1900, 2100, 2200, 2300, 2500 are leap years and
2000,2400 aren't (first case, above), or that 2000, 2400 are leap years and
1900, 2100, 2200, 2300, 2500 aren't.

   However, I'm not sure which way it is.  If it's the first way, your
function will only work for another 10 years or so.  If it's the second
way, your program's fine for another 110 years.

   Does anyone know which way it is?  (Just to satisfy that part of my
brain that killed the cat)  If I were at home, I could look it up in a
book on my bookshelf, but I'm here at school, so I'm in the dark.

-- 
======================================================================
! Stephen M. Dunn, cs3b3aj@maccs.McMaster.CA ! DISCLAIMER:           !
! This space left unintentionally blank - vi ! I'm only an undergrad !
======================================================================

ken@aiai.ed.ac.uk (Ken Johnson) (04/13/89)

In article <2394@maccs.McMaster.CA> cs3b3aj@maccs.UUCP (Stephen M. Dunn) writes:
>...  It is either that years divisible by 400 are
>_not_ leap years, or that any century year is not a leap year _except_
>for years divisible by 400.

All years divisible by 400 ARE leap years.
Other years divisible by 100 are NOT leap years.
Other years divisible by 4 ARE leap years.
Other years are NOT leap years.
-- 
Ken Johnson, AI Applications Institute, 80 South Bridge, Edinburgh EH1 1HN
E-mail ken@aiai.ed.ac.uk, phone 031-225 4464 extension 212
Expectorate the unexpectorated. Expect the unexpecfblugh.

mal@hjuxa.UUCP (LEACH) (04/13/89)

From article <2394@maccs.McMaster.CA>, by cs3b3aj@maccs.McMaster.CA (Stephen M. Dunn):
> In article <1780001@hpcc01.HP.COM> azarian@hpcc01.HP.COM (Randy Azarian) writes:
> ...
>>  total := total + + (year - 1) div 4;
> 
>    But watch out, because not every year such that year mod 4 = 0 is a leap
> year!  The strangeness in the pattern occurs on century years, but I'm not 
> sure which way round it is.  It is either that years divisible by 400 are

A year is a leap year if it is evenly divisible by 4 and not evenly divisible
by 100; unless, of course, it is divisible by 400.

1900 was not a leap year.
2000 will be.

-- 
Michael A. Leach   uucp:    {decvax,clyde,rutgers,decuac}!hjuxa!mal
		   email:   hjuxa!mal@decuac.dec.com  OR  leach@unxa.dec.com   

jackiw@cs.swarthmore.edu (Nick Jackiw) (04/14/89)

I know this ain't too helpful, but...

There's a simple (five term) non-iterative formula called Ziegler's
Congruence (or possible Zegler's Congruence --- or was it Confluence? :-))
that returns 0..6 for the day of the week of any day since the last
MAJOR calendar adjustment (1818?).

I saw it six or seven years ago in a "Gem of the Month" block in _Creative
Computing_.

Not too helpful, eh?  But it was a LOT cleaner than any of the stuff
posted here so far.



-- 
     _  _|\____    Nick Jackiw | Visual Geometry Project | Math Department
   / /_/   O>  \   ------------+-------------------------+ Swarthmore College
   |       O>   |  215-328-8225| jackiw@cs.swarthmore.edu| Swarthmore PA 19081
    \_Guernica_/   ------------+-------------------------+                 USA

mketch@pawl.rpi.edu (Michael D. Ketchen) (04/14/89)

In article <2394@maccs.McMaster.CA> cs3b3aj@maccs.UUCP (Stephen M. Dunn) writes:
>In article <1780001@hpcc01.HP.COM> azarian@hpcc01.HP.COM (Randy Azarian) writes:
>...
>>  total := total + + (year - 1) div 4;
>
>   But watch out, because not every year such that year mod 4 = 0 is a leap
>year!  The strangeness in the pattern occurs on century years, but I'm not 
>sure which way round it is.  It is either that years divisible by 400 are
>_not_ leap years, or that any century year is not a leap year _except_
>for years divisible by 400.
>      (etc. etc.)
>   Does anyone know which way it is? ...
>! Stephen M. Dunn, cs3b3aj@maccs.McMaster.CA

Every fourth year is a leap year (1988, 1992, etc.), unless it falls on the
end of a century (1800, 1900, etc), in which case it's not a leap year,
_unless_ it's a multiple of 400 (2000, 2400, etc.), in which case it _is_
a leap year.  Confusing, eh?  The following function should return TRUE if
the year passed is leap.

function IsALeap (year: integer): boolean;
(* returns TRUE if 'year' is a leap year *)
begin
  IsALeap:=FALSE;
  if ((year mod 4)=0) and ((year mod 100)<>0)
     or ((year mod 400)=0) then
    IsALeap:=TRUE
end;  (* IsALeap *)

Hope this helps...

- Mike

--------------------------------------------------------------------------------
mketch@pawl.rpi.edu (Internet) | Mike (Dave) Ketchen  | "Yes, Santa Claus, there
ketchenm@rpitsmts (Bitnet)     | Overworked Student   | is a Virginia..."
--------------------------"I say, anyone for tennis?"---------------------------

christer@zeus.cs.umu.se (Christer Ericson) (04/14/89)

In article <2684@ilium.cs.swarthmore.edu> jackiw@ilium.UUCP (Nick Jackiw) writes:
>I know this ain't too helpful, but...
>
>There's a simple (five term) non-iterative formula called Ziegler's
>Congruence (or possible Zegler's Congruence --- or was it Confluence? :-))
>that returns 0..6 for the day of the week of any day since the last
>MAJOR calendar adjustment (1818?).
>


The formula which you are refering to is called Zeller's Congruence. Actually,
the first program our students of CS has to write [in a functional language
called ML] is an implementation of this formula. Anyway, here it is:

      weekday=([2.6*m-0.2] + d + y + [y/4] + [c/4] - 2*c) mod 7

Where c,y,m,d denotes century, year (last two digits only), month, and day
respectively. [x] is the integer part of x.  The number in weekday is
interpreted as 0=Sunday, 1=Monday, 2=Tuesday, ...

In pascal it could look like this:

FUNCTION Zeller(y,m,d:INTEGER):INTEGER;
VAR c : INTEGER;
BEGIN
  c:=y DIV 100;
  y:=y MOD 100;
  Zeller:=((26*m-2) DIV 10 + d + y + y DIV 4 + c DIV 4 - 2*c) MOD 7;
END;

Oh, there is a small 'trap' in this formula and that is that the parenthesis
before the modula can be negative, and many computer modulas don't handle
negative numbers the correct way, so add [say] 777 to the left side before
doing the modula.


>     _  _|\____    Nick Jackiw | Visual Geometry Project | Math Department
>   / /_/   O>  \   ------------+-------------------------+ Swarthmore College
>   |       O>   |  215-328-8225| jackiw@cs.swarthmore.edu| Swarthmore PA 19081
>    \_Guernica_/   ------------+-------------------------+                 USA



/Christer


+-------------------------------+-------------------------------------------+
| Christer Ericson              |  Inst. for Information Processing,        |
| Internet: christer@cs.umu.se  |  University of Umea, S-90187 UMEA, Sweden |
+-------------------------------+-------------------------------------------+

bobd@ihf1.UUCP (Bob Dietrich) (04/15/89)

This procedure originally appeared in Pascal News, written by Arthur Sale if
I remember correctly. The machine-dependent portion (see comments) and
anything it references are not Arthur's fault but my own. The procedure
uses Zeller's congruence.

				Bob Dietrich
				Intel Corporation, Hillsboro, Oregon
				(503) 696-2092
		usenet:		uunet!littlei!intelhf!ihf1!bobd
		  or		tektronix!tessi!agora!ihf1!bobd
		  or		tektronix!ogccse!omepd!ihf1!bobd
		  or		tektronix!psu-cs!omepd!ihf1!bobd
=====================================

procedure timelog( var f: text);
         {*******}
{---------------------------------------------------------------}
{                                                               }
{   This procedure prints out a basic log-record on the f       }
{   file.  It avoids the well-known problems of American and    }
{   English date conventions, and the 24-hour clock confusion.  }
{                                                               }
{---------------------------------------------------------------}
const
    alfalength = 10;
 
type
    int = 0 .. 99;
    index  = 1 .. alfalength;
    alfa = packed array[ index] of char;
 
var
    year           : 01..99;         { two digits, 19xx assumed }
    month          : 1..12;          { month number             }
    day            : 1..31;          { day in month             }
    hour           : 0..23;          { 24-hour clock assumed    }
    minute         : 0..59;          { minutes past the hour    }
    second         : 0..59;          { seconds past the hour    }
 
    today,
    now            : alfa;
    adjyear        : 00..99;         { Jan & Feb are taken as   }
    adjmonth       : 1..12;          { last months of prev year }
    weekday        : 0..6;           { 0=Sunday, 1=Monday, etc  }
    adjustedhour   : 0..12;          { conventional-clock       }
 
  function makeint( string: alfa; i: index): int;
  { converts a two character digit sequence to a small integer }
 
  begin
     if string[i] = ' ' then
	string[i] := '0';
     makeint := (ord(string[i]) - ord('0')) * 10
                  + (ord( string[i+1]) - ord( '0'));
  end; {makeint}
 
begin
    { The statements between here and the next comment should   }
    { be replaced by the equivalent for your system.  Note the  }
    { ranges of the variables documented in the declarations.   }
    time(now);   date( today);
    year   := makeint( today, 8);
    { month  := makeint( today, 4); }
     case today[4] of                      { Unix returns 'DD Mmm YY ' }
     'J':
          if today[5] = 'a' then
            month := 1
          else
            if today[6] = 'n' then
                month := 6
            else
                month := 7;
     'F':
        month := 2;
     'M':
        if today[6] = 'r' then
          month := 3
        else
          month := 5;
     'A':
        if today[5] = 'p' then
          month := 4
        else
          month := 8;
     'S':
        month := 9;
     'O':
        month := 10;
     'N':
        month := 11;
     'D':
        month := 12
     end;
    day    := makeint( today, 1);
 
    hour   := makeint( now, 2);
    minute := makeint( now, 5);
    second := makeint( now, 8);

    { writeln( f, 'time = ''', now, ''', date = ''', today, ''''); } {DEBUG}
    { writeln( f, year:1, '/', month:1, '/', day:1, '   ', } {DEBUG}
    {             hour:1, ':', minute:1, ':', second:1); } {DEBUG}

    { This closes the machine-dependent part }
 
    { Compute the adjusted hour we use }
    adjustedhour:=hour mod 12;
    if (adjustedhour = 0) then adjustedhour:=12;
 
    { Adjust month and year information }
    if (month <= 2) then begin
        adjmonth:=month+10; adjyear:=year-1
    end else begin
        adjmonth:=month-2;  adjyear:=year
    end;
    { Zeller's congruence }
    weekday :=
        (((26 * adjmonth - 2) div 10) + day + adjyear +
        (adjyear div 4) + 1) mod 7;
 
    { Write the timelog out }
    case weekday of
        0: write(f,'Sunday');
        1: write(f,'Monday');
        2: write(f,'Tuesday');
        3: write(f,'Wednesday');
        4: write(f,'Thursday');
        5: write(f,'Friday');
        6: write(f,'Saturday')
    end;
    write(f,', ',(year+1900):4,' ');
    case month of
        1: write(f,'January');
        2: write(f,'February');
        3: write(f,'March');
        4: write(f,'April');
        5: write(f,'May');
        6: write(f,'June');
        7: write(f,'July');
        8: write(f,'August');
        9: write(f,'September');
       10: write(f,'October');
       11: write(f,'November');
       12: write(f,'December')
    end;
    write(f,' ',day:2,' ',adjustedhour:2,':',
        (minute div 10):1,(minute mod 10):1,':',
        (second div 10):1,(second mod 10):1);
    if (hour >= 12) then begin
        writeln(f,' PM.')
    end else begin
        writeln(f,' AM.')
    end;
end; {timelog}

R_Tim_Coslet@cup.portal.com (04/15/89)

In article: <1265@rpi.edu>
	mketch@pawl.rpi.edu (Michael D. Ketchen) gave the following
		Pascal function for leap year determination...
>
>function IsALeap (year: integer): boolean;
>(* returns TRUE if 'year' is a leap year *)
>begin
>  IsALeap:=FALSE;
>  if ((year mod 4)=0) and ((year mod 100)<>0)
>     or ((year mod 400)=0) then
>    IsALeap:=TRUE
>end;  (* IsALeap *)
>
It would be simpler to write like this...

function IsALeap (year: integer): boolean;
(* returns TRUE if 'year' is a leap year *)
begin
  IsALeap := ((year mod 4)=0) and ((year mod 100)<>0)
	      or ((year mod 400)=0) 
end;  (* IsALeap *)

                                        R. Tim Coslet

Usenet: R_Tim_Coslet@cup.portal.com
BIX:    r.tim_coslet 

cs3ia3ac@maccs.McMaster.CA (Howard Betel) (04/17/89)

In article <19040@adm.BRL.MIL> you write:
>I know this isn't quite appropriate to the list, but I really need an
>algorithm that will return the day of the week given today's date.
>Thanx in advance.

I know this is bad programming technique, but one way I implemented
this on a PC was to capture the current date in a variable.  I then
reset the clock to the date I was interested in and pulled the day
of the week right off the computer.  Let it do the work.  Dirty
but effective if it is a date in the future and not before 1984 (or
somewhere there abouts).  If you want more info, I can dig it
out of my program.

BTW Don't forget to reset the date.

--
Howard Betel
cs3ia3ac@maccs.McMaster.CA