Calendar

Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Calendar, Home

This program displays a monthly calendar for any month and year from 1752 onwards, using Zeller’s congruence to calculate the starting day of the week. The month name is matched against a packed three-character lookup string (lines 30–80), and the day-of-week calculation at lines 250–310 implements the classic Zeller algorithm with century correction. Line 220 uses PEEK 23688 (the current print column register) to detect when a row is full and break to a new line, while line 230 also PEEKs 23688 to handle automatic line wrapping. The calendar layout is printed using AT coordinates and column-position arithmetic derived from the calculated starting day Z.


Program Analysis

Program Structure

The program is divided into three logical phases:

  1. Initialisation (lines 20–30): Sets display attributes and loads the packed lookup string A$ containing month abbreviations followed by day abbreviations.
  2. Input and validation (lines 40–100): Prompts for a month name (matched against the first 36 characters of A$), then a year (must be ≥ 1752, the adoption of the Gregorian calendar in Britain).
  3. Calendar display (lines 110–310): Prints the heading, day labels, calculates the starting column, and iterates through days 1–31, with a subroutine at lines 250–310 implementing Zeller’s congruence.

Packed Lookup String

A$ at line 30 encodes all month and day abbreviations as a single concatenated string. Characters 1–36 hold the 12 three-character month codes (e.g. JAN, FEB, …), with an unusual leading CD sentinel that shifts the useful month data to positions 3–38. Characters 39 onwards hold the seven day abbreviations (SUN MON TUE WED THU FRI SAT) which are printed directly at line 130 using the slice A$(39 TO ).

The month match loop (lines 50–70) compares the first three characters of the user’s input against A$(3*M TO 3*M+2). Because A$ starts with CD, when M=1 the slice is A$(3 TO 5) = JAN, correctly offsetting past the sentinel.

Zeller’s Congruence (lines 250–310)

The subroutine calculates the day of the week for the first of the month using a standard form of Zeller’s congruence. January and February are treated as months 13 and 14 of the previous year, achieved by the variable X which adds 12 to M and decrements L (the adjusted year) when the month is 1 or 2. The century correction uses INT(P/4)-P where P=INT(L/100).

VariableRole
XMonth adjustment (adds 12 for Jan/Feb)
LAdjusted year (decremented for Jan/Feb)
PCentury value INT(L/100)
ZDay of week result (0=Sunday)

The subroutine is called twice: once at line 140 to find the starting day for positioning the cursor, and again at line 170 after incrementing M at line 160 to find the starting day of the next month — used by the end-of-month detection at line 220.

Column-Position Tracking with PEEK 23688

System variable 23688 (S_POSN column, the current print column) is PEEKed twice for layout control. At line 220, the condition 30-PEEK 23688=Z*4 compares the expected column for the next month’s first day against the current position; when they match after day 27 or later, the loop branches to line 500 (not shown in the listing) to terminate the day sequence cleanly. At line 230, PEEK 23688=2 detects when the cursor has wrapped to near the left edge, causing a newline and indent to start a new calendar row.

Key BASIC Idioms

  • Boolean arithmetic: LET Z=Z+7*(Z=0) at line 180 adds 7 when Z is zero, replacing a conditional branch. Similarly, LET X=(M=1)+(M=2) and LET L=Y-X use boolean expressions (evaluating to 1 or 0) for compact Zeller adjustments.
  • Conditional string printing: PRINT " " AND I<10 at line 210 prints a leading space for single-digit day numbers, aligning columns without an IF statement.
  • String slicing for lookup: Month matching uses computed string slices rather than a DATA/READ array, saving memory.

Anomalies and Notes

  • Line numbers 190 and 320 onwards are absent from the listing; this may indicate renumbering was applied, or that lines were deleted. The jump to line 500 at line 220 targets code not shown in the listing.
  • The 31-day loop (lines 200–240) does not account for months with fewer than 28, 29, 30, or 31 days by itself — the early-exit condition at line 220 (comparing print column to next month’s start day) handles this implicitly for months of varying length, though correctness depends on the behaviour of code at line 500.
  • The BORDER 5: PAPER 6 at line 20 sets cyan paper and magenta border, with POKE 23658,8 enabling caps lock.

Content

Appears On

This tape is a compilation of programs from user group members (Robert Burton, David Baulch, Frank Bouldin, Chuck Dawson, Ryan
One of a series of library tapes. Programs on these tapes were renamed to a number series. This tape contained

Related Products

Related Articles

Related Content

Image Gallery

Calendar

Source Code

   20 POKE 23658,8: BORDER 5: PAPER 6
   30 LET A$="CDJANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDECSUN MON TUE WED THU FRI SAT"
   40 INPUT "ENTER MONTH ";B$
   50 FOR M=1 TO 12
   60 IF B$(1 TO 3)=A$(3*M TO 3*M+2) THEN GO TO 90
   70 NEXT M
   80 GO TO 40
   90 INPUT "ENTER YEAR ";Y
  100 IF Y<1752 THEN PRINT "YEAR CANNOT BE LESS THAN 1752": GO TO 90
  110 CLS 
  120 PRINT AT 3,10;B$;" ";Y
  130 PRINT AT 6,3;A$(39 TO )
  140 GO SUB 250
  150 PRINT AT 8,Z*4+3;
  160 LET M=M+1
  170 GO SUB 250
  180 LET Z=Z+7*(Z=0)
  200 FOR I=1 TO 31
  210 PRINT " " AND I<10;I;"  ";
  220 IF I>27 AND 30-PEEK 23688=Z*4 THEN GO TO 500
  230 IF PEEK 23688=2 THEN PRINT ''"   ";
  240 NEXT I
  250 LET X=(M=1)+(M=2)
  260 LET L=Y-X
  270 LET X=M+X*12
  280 LET P=INT (L/100)
  290 LET Z=INT (13*(X+1)/5)+INT (5*L/4)+INT (P/4)-P
  300 LET Z=Z-7*INT (Z/7)
  310 RETURN 

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

People

No people associated with this content.

Scroll to Top