--- title: "Calendar" id: 71444 type: "computer_media" slug: "calendar-6" url: "http://localhost/computer_media/calendar-6/" markdown_url: "http://localhost/computer_media/calendar-6.md" published_at: "2026-09-09T09:05:27+00:00" modified_at: "2026-09-09T09:05:28+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/09/calendar-imre-2.png" excerpt: "A graphical calendar generator spanning 1583 to 9999 AD, with Zeller's Congruence day calculation, printer heading options, and full-year print mode." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "1984" slug: "year-1984" taxonomy: "post_tag" url: "http://localhost/tag/year-1984/" - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" indiv: - name: "Algis Gedris" slug: "algis-gedris" taxonomy: "indiv" url: "http://localhost/indiv/algis-gedris/" - name: "Imre Auersbacher" slug: "imre-auersbacher" taxonomy: "indiv" url: "http://localhost/indiv/imre-auersbacher/" genre: - name: "Calendar" slug: "calendar" taxonomy: "genre" url: "http://localhost/type/calendar/" media_type: "Program" programmers: - name: "Imre Auersbacher" slug: "imre-auersbacher" taxonomy: "indiv" url: "http://localhost/indiv/imre-auersbacher/" - name: "Algis Gedris" slug: "algis-gedris" taxonomy: "indiv" url: "http://localhost/indiv/algis-gedris/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Calendar%20(1984)(Auersbacher%2C%20Imre)(TS2068)(US)(Program).zip" tsrun_member: "Calendar (1984)(Auersbacher, Imre)(TS2068)(US)(Program).tap" mediadate: "1984" images: - url: "http://localhost/wp-content/uploads/2026/09/calendar-imre-2.png" - url: "http://localhost/wp-content/uploads/2026/09/calendar-imre.png" media_type_tags: "Calendar" --- # Calendar This program generates and displays a graphical calendar for any month between 1583 and 9999 AD, using the Zeller’s Congruence algorithm to calculate the day of the week for any given month and year, including correct leap year handling. The calendar grid is drawn using PLOT and DRAW commands to produce ruled lines, with day numbers positioned via PRINT AT within the cells. An introductory menu subroutine at line 410 allows the user to select custom LPRINT headings—such as “Month of Birth” or “Year of Birth”—or enter up to 32 characters of freeform text, optionally centered, before printing. The “Y” mode loops through all 12 months automatically, sending each to the printer via COPY and LPRINT, while “M” mode prints a single month. POKE 23609 adjusts the printer’s line feed delay and POKE 23658 enables CAPS LOCK at startup. *** ### Program Structure The program is organized into two main sections: the main calendar logic (lines 10–400) and a menu/heading subroutine (lines 410–790). Execution begins with hardware POKEs and a call to the subroutine at line 410, which presents the heading-selection menu. On return, the main loop at line 80 accepts a mode character (`T$`: `"Y"`, `"M"`, or `"D"`), then collects month and year inputs before computing and rendering the calendar grid. ### Day-of-Week Calculation (Zeller’s Congruence) Lines 140–170 implement a variant of Zeller’s Congruence. January and February are treated as months 13 and 14 of the previous year by adjusting `E` and `C`. The formula at line 160 computes a raw day index using century, year, and month terms, and line 170 reduces it modulo 7, adding 1 to produce a 1-based Sunday-first column offset stored in `D`. - `E = B - (A < 3)` — adjusts year for Jan/Feb - `C = A + 12*(A < 3) + 1` — adjusts month index - `D = INT(E/400) - INT(E/100) + INT(1.25*E) + INT(2.6*C)` — raw Zeller value - `D = D - 7*INT(D/7) + 1` — maps to 1–7 (Sun–Sat) ### Leap Year Handling Line 210 handles February’s day count. It starts with 28, then tests the compound leap-year rule: divisible by 4 AND NOT by 100, OR divisible by 400. The Boolean arithmetic uses multiplication for AND and addition for OR, a standard Sinclair BASIC idiom. ### Calendar Grid Rendering Rather than using character graphics, the grid is drawn with PLOT/DRAW commands (lines 240–280). A horizontal header separator is drawn at line 250, six horizontal row dividers follow in the loop at line 270, and six vertical column dividers are drawn in the loop at line 280. Day numbers are sourced from the pre-built string `Z$` at line 70, which contains all 31 two-character day-number substrings concatenated. Line 320 builds `C$` by padding with spaces proportional to the starting day offset (`2*D-2` spaces), then appending `Z$`. The print loop at lines 330–350 walks through `C$` two characters at a time, advancing column by 4 and row by 2 at each week boundary. ### Operating Modes | T$ value | Behavior | | --- | --- | | `"Y"` | Loops A from 1 to 12, prints each month to screen via COPY and adds LPRINT year banner | | `"M"` | Displays a single month and sends it to the printer via COPY | | `"D"` | Display-only; no printing | ### Heading Menu Subroutine (Lines 410–790) The subroutine presents labeled options and polls `INKEY$` in a tight loop (lines 520–580). Each key triggers an LPRINT heading or a sub-flow. The `"P"` option (lines 620–760) prompts for up to 32 characters of custom text, optionally centering it by computing `L = (32 - LEN Z$) / 2` and using `LPRINT TAB INT L`. The `"S"` option at line 790 saves the program to tape. ### Notable Techniques and Idioms - `POKE 23609,20` sets the printer LPRINT delay; `POKE 23658,8` enables CAPS LOCK — both are system variable manipulations common in Sinclair BASIC utilities. - Boolean expressions like `(A<3)` evaluate to 1 or 0 and are used directly in arithmetic, avoiding IF statements in the Zeller calculation. - `VAL "number"` is not used here; GO TO targets are literal line numbers. - The month-name array is a `DIM M$(12,9)` fixed-width string matrix loaded from DATA at line 60, padded automatically to 9 characters. - The program title contains the misspelling “CALENDER” (should be “CALENDAR”), which appears consistently in both the display strings and the SAVE filename `"Calende"`. - There is a case inconsistency: `T$` is set by INPUT at line 80 but compared as lowercase `t$` at lines 130 and 220 — on Spectrum-family systems these refer to the same variable, as variable names are case-insensitive in the tokenizer. ### Potential Anomalies - Line 50 prints a heading but is executed before month/year inputs; it is immediately overwritten by `CLS` at line 120, so it only flashes briefly. - Line 590 is unreachable from the normal INKEY$ polling loop (lines 520–580 skip from 580 back to 520), making the extra LPRINT calls at line 590 dead code. - The `LPRINT` year banner at line 290 only fires when `T$="Y"` and `A=1`, so yearly print runs get a year header only on the January page. - After a full run, line 380 asks to repeat and branches to `RUN`, which re-initializes all variables and re-enters the heading menu, rather than branching to line 80 to skip the menu. ## Source Code ``` 10 POKE 23609,20:POKE 23658,8 20 REM \*1984 BY I. AUERSBACHER: MODIFIED BY ALGIS E. GEDRIS 30 BORDER 5:BRIGHT 1:CLS :DIM M$(12,9) 40 BEEP .1,30:GO SUB 410:CLS 50 PRINT ' PAPER 6;" *** CALENDER(1583-9999 AD) *** " 60 RESTORE :FOR Z=1 TO 12:READ M$(Z):NEXT Z 70 LET Z$=" 1 2 3 4 5 6 7 8 910111213141516171819202122232425262728293031":BEEP .05,20 80 INPUT "Y-YEAR, M-PRINT MO, D-DISPLAY:"; LINE T$ 90 IF T$="Y" THEN GO TO 110 100 INPUT "MONTH (1-12):";A:IF A<1 OR A>12 THEN BEEP .5,-20:GO TO 100 110 INPUT "YEAR (YYYY):";B:IF B<1582 OR B>9999 THEN BEEP .5,-20:GO TO 110 120 CLS 130 IF t$="Y" THEN FOR X=1 TO 12:LET A=X 140 LET B= INT B:LET E=B-(A<3) 150 LET C=A+12*(A<3)+1 160 LET D= INT (E/400)- INT (E/100)+ INT (1.25*E)+ INT (2.6*C) 170 LET D=D-(7* INT (D/7))+1 180 IF (A=4)+(A=6)+(A=9)+(A=11) THEN LET C=30 190 IF (A=1)+(A=3)+(A=5)+(A=7)+(A=8)+(A=10)+(A=12) THEN LET C=31 200 IF A <>2 THEN GO TO 220 210 LET C=28:IF (B/4= INT (B/4))*(B/100 <> INT (B/100))+(B/400= INT (B/400)) THEN LET C=29 220 IF t$="Y" THEN CLS 230 PRINT " *****************************" 240 PLOT 10,132:DRAW 225,0:DRAW 0,-112:DRAW -225,0:DRAW 0,112 250 PLOT 10,118:DRAW 225,0 260 PRINT AT 6,2;"SU MO TU WE TH FR SA":PRINT AT 3,0; 270 FOR Z=1 TO 6:PLOT 10,116-(Z-1)*16:DRAW 225,0:NEXT Z 280 FOR Z=1 TO 6:PLOT 40+(Z-1)*32,132:DRAW 0,-112:NEXT Z 290 IF T$="Y" AND A=1 THEN LPRINT " \{20}\{1}>>>>>>>>>>>\{20}\{0} ";B;" \{20}\{1}<<<<<<<<<<<<\{20}\{0}":LPRINT :LPRINT 300 IF T$="Y" THEN PRINT TAB 12;M$(A):GO TO 320 310 PRINT TAB 8;M$(A); TAB 18;B 320 DIM C$(74):LET J=8:LET K=2:LET C$=C$( TO 2*D-2)+Z$ 330 FOR Z=1 TO C+D-1:PRINT AT J,K;C$(2*Z-1 TO 2*Z):LET K=K+4 340 IF (Z/7= INT (Z/7)) THEN LET J=J+2:LET K=2 350 NEXT Z 360 IF T$="Y" THEN COPY :NEXT X 370 IF T$="M" THEN COPY 380 INPUT "ANOTHER YEAR OR MONTH? (Y/N):";Y$:IF Y$ <>"N" THEN RUN 390 DATA "JANUARY","FEBRUARY","MARCH","APRIL","MAY","JUNE","JULY","AUGUST","SEPTEMBER","OCTOBER","NOVEMBER","DECEMBER" 400 GO TO 10 410 CLS 420 PRINT AT 5,0; PAPER 6;" *** CALENDER(1583-9999 AD) *** " 430 PRINT '' 440 PRINT " SPECIAL CALENDER HEADINGS"; OVER 1; AT 8,0;" _________________________" 450 PRINT ' 460 PRINT " SPECIAL \{20}\{1}P\{20}\{0}RINTING ...... P" 470 PRINT " THIS \{20}\{1}C\{20}\{0}ALENDAR IS FOR:...C" 480 PRINT " \{20}\{1}M\{20}\{0}ONTH OF BIRTH .........M" 490 PRINT " \{20}\{1}Y\{20}\{0}EAR OF BIRTH...........Y" 500 PRINT " \{20}\{1}N\{20}\{0}O HEADING..............N" 510 PRINT " \{20}\{1}S\{20}\{0}AVE....................S" 520 IF INKEY$="S" THEN GO TO 790 530 IF INKEY$="M" THEN GO TO 600 540 IF INKEY$="Y" THEN GO TO 610 550 IF INKEY$="P" THEN GO TO 620 560 IF INKEY$="N" THEN RETURN 570 IF INKEY$="C" THEN GO TO 770 580 GO TO 520 590 LPRINT :LPRINT :GO TO 520 600 LPRINT :LPRINT " MONTH of BIRTH":LPRINT :GO TO 520 610 LPRINT :LPRINT " YEAR of BIRTH":LPRINT :GO TO 520 620 CLS :PRINT :PRINT :PRINT "DO YOU WANT THE INPUT CENTERED?" 630 IF INKEY$="Y" THEN GO TO 660 640 IF INKEY$="N" THEN GO TO 720 650 GO TO 630 660 PRINT :PRINT " ENTER UP TO 32 CHARACTERS." 670 INPUT Z$:IF LEN Z$>32 THEN GO TO 670 680 LET L=(32- LEN Z$)/2 690 LPRINT TAB INT L;Z$ 700 LPRINT '' 710 GO TO 410 720 PRINT :PRINT "Enter up to 32 characters." 730 INPUT Z$:IF LEN Z$>32 THEN GO TO 730 740 LPRINT Z$ 750 LPRINT '' 760 GO TO 410 770 LPRINT :LPRINT " THIS CALENDAR IS FOR:" 780 LPRINT :GO TO 410 790 SAVE "Calende" LINE 1:BEEP .5,20:REM PRINT INK 2;AT 20,4;"\{20}\{1} REWIND THE TAPE \{20}\{0}";AT 21,2;"\{20}\{1}*** AND PLAY TO VERIFY ***\{20}\{0}":VERIFY "":GO TO 1 ```