!pr1
Computing the Day of Week...............Bob Sander-Cederlof

Within reasonable limits, it should be possible for a clock/ calendar card to automatically set the day-of-week number when given the year, month, and day.  The algorithm for deriving day-of-week from the date is simple enough.  However, as the algorithm is stated in all my reference material, it involves multiplication and division by numbers that are not simple powers of two.

I have simplified the algorithm so that it will work over the range from March 1, 1984 through December 31, 2083.  That should be an adequate range for any Apple products!

Years evenly divisible by 4 are leap years, having 366 days.  The years ending in 00 are exceptions, unless they are divisible by 400.  Thus 1900 was not a leap year, 2100 will not be a leap year, but 2000 is a leap year.

My algorithm started out as a method for converting a Y-M-D date to a Julian date, which is a unique number that was 0 several thousand years ago.  I could get the remainder after dividing the Julian date by 7, and use it for a day-of-week index.  However, the numbers get rather large; they won't fit in one byte.

By converting all the intermediate values to their modulo 7 equivalents, I can keep the result down to byte-size.  Here is an Applesoft program which implements my algorithm:

!lm+3
100 DIM MD(11),D$(6)
110 DATA 3,6,1,4,6,2,5,0,3,5,1,4
120 DATA SUN,MON,TUES,WEDNES,THURS,FRI,SATUR
130 FOR I=0 TO 6 : READ M : MD(I)=M : NEXT
140 FOR I=0 TO 11: READ D$: D$(I)=D$: NEXT
200 INPUT Y,M,D
210 M = M-3
220 IF M<0 THEN M=M+12 : Y=Y-1
230 Y=Y-1984
240 W = Y + INT(Y/4) + MD(M) + D
250 IF W>6 THEN W=W-7 : GO TO 250
260 PRINT D$(W)"DAY"
270 GO TO 200
!lm-3

Lines 100-140 build two arrays.  The MD array holds a modulo 7 number for the number of days preceding each month in a normal year (not leap year).  The D$ array holds the names of the days, shortened by the last three letters.

Line 200 waits for you to type in the year, month, and day as three numbers.  I did not add any error testing, but I expect the year to be from 1984 up.  The month should be a number from 1 to 12, and the day from 1 to 31.

Lines 210-220 adjust the month number.  I move January and February to the end of the previous year, like it must have been in the olden days.  That makes leap day the last day of the year, where it belongs.  It also makes the month names for Sept-, Oct-, Nov-, and Dec-ember make linguistic sense!  March becomes the first month, December the tenth, and so on.  Internally, the value of the variable M will be a number from 0 to 11.

Line 230 adjusts the year to start at 1984.  Line 240 adds up the various day-values.  We add Y, the number of the years since 1984, because 365 = 1 mod 7.  We add INT(Y/4) to get the leap days.  MD(M) adds in the bias for the number of days beyond an integral number of weeks to the end of the previous month.  D adds in the day number.  Altogether we have a number which is still less than 256, and fits in one byte in a machine language version of the algorithm.

Line 250 subtracts 7 (whole weeks) until we get to a number less than 7.  The result is the day number in a week with 0 meaning Sunday, 1 meaning Monday, and so on.  Line 260 prints the day name, and line 270 lets us try another date.

After making sure of my method with the Applesoft program, I coded it in assembly language.  The program which follows is set up to be used from inside Applesoft, and I also list here the Applesoft driver.  I did it this way to make it easy to test my assembly language code.  Later I will probably put the code inside a larger package which sets the time and day on my clock card.  Once it is in there, I can forever forget about the need to tell the card what day of week it is.
!np







Lines 1020-1050 are the variables used to communicate with the Applesoft test program, by way of PEEKs and POKEs.  The program assumes that only the last two digits of the year are used, so that YEAR is a number from 84 to 99 for 1984 to 1999; values from 0 to 83 signify years from 2000 to 2083.

Lines 1080-1130 change the year number, which runs 84...99 and 00...83 to a value based at 1984, running from 00 to 99.  00 means 1984, 99 means 2083.

Lines 1150-1210 are equivalent to the Applesoft lines 210 and 220 in the first program above.  Lines 1220-1290 are equivalent to the Applesoft line 240.  Lines 1300-1340 reduce the result to a modulo 7 remainder.  The final value, a number from 0 to 6, is stored in line 1350 where an Applesoft driver can find it by PEEK(771).

Here is my Applesoft test program.  This time I went in for a little range checking on the input values for year, month, and day.

!lm+3
100 DIM D$(6)
110 DATA SUN,MON,TUES,WEDNES,THURS,FRI,SATUR
120 FOR I=0 TO 6 : READ M : MD(I)=M : NEXT
200 INPUT "YEAR (1984-2083):  ";Y
210 IF Y<1984 OR Y>2083 THEN 200
220 Y = Y - INT(Y/100)*100
230 POKE 768,Y
300 INPUT "    MONTH (1-12):  ";M
310 IF M<1 OR M>12 THEN 300
320 POKE 769,M
400 INPUT "      DAY (1-31):  ";D
410 IF D<1 OR D>31 THEN 400
420 POKE 770,D
500 CALL 772
510 W = PEEK(771)
600 PRINT D$(W)"DAY"
610 GO TO 200
