Computing the day of the week.

My first computer program

It must be the autumn of 1983. When I visited a friend of mine (a radio amateur), he showed me his new toy, the Sinclair ZX-81. one of the cheapest home computers at the time. This was not the first time a saw a computer and I had definitely entered some BASIC commands before. A year earlier I had visited an uncle of mine who was the proud owner of an Acorn Atom. It showed text on a TV-screen. As I recall, I entered a simple BASIC program to solve quadratic equations and I played with mathematical functions that could be evaluated in BASIC. And there was a version of Space Invaders that you could load from cassette tape. This was all very fascinating and I knew that I was going to have a computer sooner or later.

But back to the ZX-81. This too could show text and simple graphics on a TV screen and it too could load games from cassettes. It too had BASIC in ROM. This could be yours for less than 200 guilders including the 16 kB RAM extension that you were almost required to have. This machine could run a simple flight simulator program and I was truly amazed that this was possible on such a simple computer.

But programming was the thing I was most interested in, more than playing games. Calculating the week day for any given date was a problem that I should be able to tackle and so I did. I think I wrote the program down on paper after I ran it successfully on the ZX81, so I could enter it later when I did get a computer. The program may have looked a bit like the listing below. The original version certainly did not have REM statements, that would be a waste of memory (and would be too tedious to type on the ZX-81) and the original was in Dutch. But the algorithm was definitely very similar to what is shown, including the long clumsy lists of IF-statements. I did not know arrays at the time. I certainly did not use a fancy formula, such as Zeller's congruence. Download the program here to try in with your own BASIC interpreter.

 10 REM COMPUTE DAY OF THE WEEK
 20 PRINT "ENTER DAY (1-31)"
 30 INPUT D
 40 IF D>=1 AND D<=31 THEN GOTO 70
 50 PRINT "DAY OUT OF RANGE"
 60 GOTO 20
 70 PRINT "ENTER MONTH (1-12)"
 80 INPUT M
 90 IF M>=1 AND M<=12 THEN GOTO 120
100 PRINT "MONTH OUT OF RANGE"
110 GOTO 70
120 PRINT "ENTER YEAR (1901-2099)"
130 INPUT Y
140 IF Y>=1901 AND Y<=2099 THEN GOTO 170
150 PRINT "YEAR OUT OF RANGE"
160 GOTO 120
170 REM SET L=1 FOR LEAP YEAR, OTHERWISE LET L=0
180 LET L=0
190 IF 4*INT(Y/4)=Y THEN LET L=1
200 REM ADD NUMBER OF YEARS TO DAY, EACH YEAR STARTS A DAY LATER
210 LET D=D+Y
220 REM ADD NUMBER OF LEAP YEARS BEFORE THIS YEAR
230 LET D=D+INT((Y-1)/4)
240 REM ADD DAYS OF PRECEDING MONTHS
250 IF M>1 THEN LET D=D+31
260 IF M>2 THEN LET D=D+28+L
270 IF M>3 THEN LET D=D+31
280 IF M>4 THEN LET D=D+30
290 IF M>5 THEN LET D=D+31
300 IF M>6 THEN LET D=D+30
310 IF M>7 THEN LET D=D+31
320 IF M>8 THEN LET D=D+31
330 IF M>9 THEN LET D=D+30
340 IF M>10 THEN LET D=D+31
350 IF M>11 THEN LET D=D+30
360 REM THE FOLLOWING ADDITION WAS FOUND BY TRIAL AND ERROR
370 LET D=D+5
380 REM NOW DO MODULO 7
390 LET D=D-7*INT(D/7)
400 IF D=0 THEN LET D$="SUNDAY"
410 IF D=1 THEN LET D$="MONDAY"
420 IF D=2 THEN LET D$="TUESDAY"
430 IF D=3 THEN LET D$="WEDNESDAY"
440 IF D=4 THEN LET D$="THURSDAY"
450 IF D=5 THEN LET D$="FRIDAY"
460 IF D=6 THEN LET D$="SATURDAY"
470 PRINT D$
  
This program is written in such a way it could run on the ZX-81. So it has only one statement per line (but a statement is allowed after IF..THEN) and every assignment statement starts with LET. Sinclair BASIC requires this, other versions do not. And ZX-81 does not have an END statement (it does have STOP, but this is not required).

The algorithm is explained as follows:

Using arrays

Early in 1984 our family bought a used Texas Instruments TI-99/4A computer. This also had BASIC in ROM and it had 16kB of RAM, which I knew was enough. As opposed to the ZX-81 it had a real keyboard, colour graphics and sound. It came with three game cartridges: Munch Man, TI Invaders and Parsec and we spent many hours with these games. But for me programming was the main subject and I would soon be quite disappointed.

The TI computer had its own BASIC dialect. On the one hand it had many more features than ZX-81 BASIC, but on the other hand, it lacked some features that ZX-81 BASIC did have. And I thought: if the ZX-81 has it, every other computer must have it too. Like the ZX-81, the TI supported just one statement per line, but the IF statement could not have a statement after THEN, but just a line number (and you could specify another line number with ELSE). By the way, this is what ANSI Minimal BASIC specified and many early BASIC version on mainframes and minicomputers had it that way. As my original program contained many statements after IF..THEN, this was the first stumbling block. I could rewrite the program by using additional lines between the IF statements and then skip each of these lines in the IF statement, like this:

250 IF M<=1 THEN 260
255 D=D+31		 
260 IF M<=2 THEN 270
...			
  

But I did not feel like almost doubling the number of lines in the program. But after a little bit of learning, I came up with a solution that used arrays. The program may have looked like this one

  
100 REM COMPUTE DAY OF THE WEEK
110 DIM H(12)
120 H(1)=0
130 FOR I=2 TO 12
140 READ D
150 H(I)=H(I-1)+D
160 NEXT I
170 DIM D$(7)
180 FOR I=1 TO 7
190 READ D$(I)
200 NEXT I
210 INPUT "ENTER DAY (1-31)";D
220 IF (D>=1) * (D<=31) THEN 250
230 PRINT "DAY OUT OF RANGE"
240 GOTO 210
250 INPUT "ENTER MONTH (1-12)";M
260 IF (M>=1) * (M<=12) THEN 290
270 PRINT "MONTH OUT OF RANGE"
280 GOTO 250
290 INPUT "ENTER YEAR (1901-2099)";Y
300 IF (Y>=1901) * (Y<=2099) THEN 330
310 PRINT "YEAR OUT OF RANGE"
320 GOTO 290
330 REM IF CURRENT YEAR IS LEAP YEAR AND WE ARE IN MARCH OR LATER, ADD A DAY
340 IF (4*INT(Y/4)<>Y) + (M<3) THEN 360
350 D=D+1
360 REM ADD NUMBER OF YEARS TO DAY, EACH YEAR STARTS A DAY LATER
370 D=D+Y
380 REM ADD NUMBER OF LEAP YEARS BEFORE THIS YEAR
390 D=D+INT((Y-1)/4)
400 REM ADD NUMBER OF DAYS IN PRECEDING MONTHS.
410 D=D+H(M)
420 REM THE FOLLOWING ADDITION WAS FOUND BY TRIAL AND ERROR
430 D=D+5
440 REM NOW DO MODULO 7
450 D=D-7*INT(D/7)
460 PRINT D$(D+1)
470 END
480 REM DAYS IN MONTHS JAN-NOV
490 DATA 31,28,31,30,31,30,31,31,30,31,30
500 REM NAMES OF DAYS
510 DATA "SUNDAY","MONDAY","TUESDAY","WEDNESDAY","THURSDAY","FRIDAY","SATURDAY"
    

This program, may run unmodified on the TI-99/4A, except that it required a colon after the input prompt instead of a semicolon. It only uses the form of the IF-statement with a line number after THEN and I replaced AND and OR (that TI-Basic did not have) with * and +, as was commonly done on this machine.

The algorithm itself is the same as in the first program, but it uses two arrays. Both are read from DATA lines in two loops at the start of the program.

No, the disappointment about programming on the TI computer was not caused by the need to do a bit of extra learning to port my program to it. It was caused by the way the machine could not be programmed in machine code and many of the hardware features simply could not be used without buying additional expensive cartridges.

Zeller's congruence

Now most programs use a formula known as Zeller's congruence to compute the day of the week, like this program does.

10 REM COMPUIE DAY OF THE WEEK
20 DIM D$(7)
30 FOR I=1 TO 7:READ D$(I):NEXT I
40 INPUT "ENTER DAY (1-31)";D
50 IF D<1 OR D>31 THEN PRINT "DAY OUT OF RANGE":GOTO 40
60 INPUT "ENTER MONTH (1-12)";M
70 IF M<1 OR M>12 THEN PRINT "MONTH OUT OF RANGE":GOTO 60
80 INPUT "ENTER YEAR (1582-2999)";Y
90 IF Y<1582 OR Y>2999 THEN PRINT "YEAR OUT OF RANGE":GOTO 80
100 IF M<3 THEN M=M+12:Y=Y-1
110 D=D+5+INT(13*(M+1)/5)+Y+INT(Y/4)-INT(Y/100)+INT(Y/400)
120 D=D-7*INT(D/7)+1: REM D MOD 7 + 1
130 PRINT D$(D)
140 INPUT "ANOTHER DAY (Y/N)";Y$
150 IF Y$="Y" THEN GOTO 40
160 END
170 DATA "MONDAY","TUESDAY","WEDNESDAY","THURSDAY","FRIDAY","SATURDAY","SUNDAY"  
   

This program implements the full Gregorian date rule, as opposed to the previous two programs. The computation of the weekday is done in just three lines: 100-120, so let's explain it