This program calculates the day of the week for any date in the 20th century (1900–1999). It accepts a year, month, and day as inputs, then uses a month-offset table encoded across several IF statements to compute a running total. The day-of-week index is reduced modulo 7 via a subtract-and-loop technique rather than the MOD operator. The three-character day abbreviations are packed into a single string A$ and extracted using a calculated substring slice.
Program Analysis
Program Structure
The program is short and linear, running from line 10 to line 250 with no subroutines. Input is collected at lines 10–70, the day-of-week calculation occupies lines 80–230, and the result is printed at line 240.
- Lines 10–70: Input validation and collection (year constrained to 1900–1999, month and day unconstrained beyond that)
- Lines 80–100: Derive a two-digit year value from the string representation of
Y - Lines 110–180: Accumulate month and leap-year offsets into
T - Lines 190–230: Add the day, then reduce modulo 7 by looping
- Line 240: Print the result using a packed day-name string
Day-of-Week Algorithm
The algorithm is a simplified form of the Doomsday or tabular weekday calculation, restricted to the 20th century so that only the last two digits of the year need to be considered. Line 100 extracts those digits from the string form of Y using a substring slice (Y$(3 TO 4)), avoiding any arithmetic on the full year number. Line 110 computes INT(T + T/4), which accumulates the year offset plus one day per four years as a rough leap-year correction.
Lines 120–170 add fixed per-month offsets. April and July (offsets 0) are absent from the IF chain, acting as the implicit base case. The offsets used are:
| Month(s) | Offset added |
|---|---|
| January, October | +1 |
| February, March, November | +4 |
| April, July | +0 (implicit) |
| May | +2 |
| June | +5 |
| August | +3 |
| September, December | +6 |
Leap-Year Adjustment
Line 180 applies a special correction for January and February in leap years: if the year is not 1900 (which was not a leap year despite being divisible by 4) and the year is divisible by 4 and the month is January or February, T is incremented by 1. This correctly handles the anomaly of 1900 without needing a full Gregorian century check, since the valid range is limited to 1900–1999 and no other century boundary appears.
Modulo-7 Reduction by Looping
Rather than using a MOD operation, lines 200–230 subtract 7 from T repeatedly until T is zero or negative, then add 7 back once (line 230). This yields a value of T in the range 1–7. The loop is implemented with a bare GOTO pair, which was common in early BASIC due to the absence of a built-in modulo function on the ZX81.
Packed Day-Name String
All seven day abbreviations are concatenated into the single string A$ at line 80: "SUNMONTUEWEDTHUFRISAT". Each name occupies exactly three characters, so the day at index T is extracted with the slice A$(T*3-2 TO T*3). This avoids a DATA/READ structure or an array of strings, saving memory.
Notable Idioms and Techniques
- String slicing to extract the two-digit year (
Y$(3 TO 4)) avoids aMOD 100calculation. - The subtract-and-loop modulo at lines 200–230 is a classic early-BASIC workaround.
- Month 4 (April) and month 7 (July) carry zero offset and so are simply absent from the IF chain, keeping the code compact.
- Input validation at line 30 rejects years outside 1900–1999 with a direct
GOTO 20, but month and day inputs receive no bounds checking, which could yield incorrect output for invalid dates.
Bugs and Anomalies
No bounds checking is performed on the month (line 50) or day (line 70) inputs. An out-of-range month such as 13 would not match any IF statement, adding zero offset, and would silently produce a wrong result. Similarly, an invalid day number would not be caught. The year constraint at line 30 is the only guard in the program.
Content
Source Code
1 REM "CALENDAR1"
10 PRINT "ENTER YEAR"
20 INPUT Y
30 IF Y<1900 OR Y>1999 THEN GOTO 20
40 PRINT "ENTER MONTH(JAN=1 TO DEC=12)"
50 INPUT M
60 PRINT "NOW ENTER DATE"
70 INPUT D
80 LET A$="SUNMONTUEWEDTHUFRISAT"
90 LET Y$=STR$ Y
100 LET T=VAL Y$(3 TO 4)
110 LET T=INT (T+T/4)
120 IF M=1 OR M=10 THEN LET T=T+1
130 IF M=2 OR M=3 OR M=11 THEN LET T=T+4
140 IF M=5 THEN LET T=T+2
150 IF M=6 THEN LET T=T+5
160 IF M=8 THEN LET T=T+3
170 IF M=9 OR M=12 THEN LET T=T+6
180 IF Y<>1900 AND Y/4-INT (Y/4)=0 AND (M=1 OR M=2) THEN LET T=T+1
190 LET T=T+D
200 LET T=T-7
210 IF T<=0 THEN GOTO 230
220 GOTO 200
230 LET T=T+7
240 PRINT D;"/";M;"/";Y;" IS/WAS ON A ";(A$(T*3-2 TO T*3))
250 STOP
260 SAVE "1017%8"
270 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
