Moon Phase Calculator

This file is part of and TS-2068 Computer Programs. Download the collection to get this file.
Developer(s): Imre Auersbacher
Date: 1985
Type: Program
Platform(s): TS 2068
Tags: Astronomy

This program calculates and displays the dates and times of the four primary lunar phases — New Moon, First Quarter, Full Moon, and Last Quarter — for any year between 1000 and 4000. It implements Jean Meeus’s astronomical algorithms, using Julian Day Numbers and a series of trigonometric correction terms for the Sun’s mean anomaly, Moon’s mean anomaly, and Moon’s argument of latitude. Output can be directed either to the TV screen via OPEN #4,”s” or to a printer via OPEN #4,”p”. Six user-defined graphics characters (UDGs “a” through “f”) are loaded from DATA statements to render decorative moon-phase symbols alongside each event.


Program Analysis

Program Structure

The program is organized into a set of clearly delineated subroutines, a main initialization block, and a top-level calculation loop. The entry point at line 8 jumps directly to line 1000, where string tables, UDGs, and the user interface are set up before control passes to the main phase-calculation loop at line 50.

LinesRole
1–8REM headers and entry redirect
10–35Output formatting / date printing subroutine
50–70Main phase-calculation loop (iterates over lunation index j)
100–145Subroutine: compute base Julian Date and mean anomaly terms
150–160Subroutine: correction terms for New Moon / Full Moon phases
200–230Subroutine: correction terms for Quarter phases
300–370Subroutine: Julian Day → calendar date conversion
1000–1300Initialization, UI, UDG loading, output device selection
2000–2100DATA blocks for UDG bitmaps
3000SAVE and STOP
9000End-of-year handler: linefeed, close channel, beep

Astronomical Algorithm

The core calculation follows Jean Meeus’s method for finding the Julian Ephemeris Date of each lunar phase. The lunation index k is derived from the year at line 50 as (y-1900)*12.3685, truncated to an integer. For each quarter, k is offset by 0, 0.25, 0.5, or 0.75, then passed through subroutine 100 to calculate the time parameter t = k/1236.85, polynomial terms t2 and t3, and the base Julian Date at line 120.

Lines 130–140 compute three angular arguments in radians: the Sun’s mean anomaly (m), the Moon’s mean anomaly (n), and the Moon’s argument of latitude (f). Subroutines 150 and 200 apply a multi-term trigonometric correction sum c to refine the Julian Date. Subroutine 200 also applies small additive corrections to the quarter phases depending on whether g=2 (First Quarter) or g=4 (Last Quarter).

Julian Day to Calendar Conversion

Subroutine 300 converts the computed Julian Day Number to a Gregorian (or Julian) calendar date. The branch at lines 310–320 handles the Gregorian calendar reform cutoff of JD 2299161 (October 15, 1582). The intermediate variables a, b, c, d, and e follow the standard Meeus conversion formulas to extract day-of-year, month, and year, with line 360 correcting the year for January/February.

String Table Indexing

All lookup tables are stored as packed strings and indexed by arithmetic, a common memory-efficient idiom:

  • d$ — two-character day abbreviations (“SuMoTuWeThFrSa”), indexed as d$(2*d-1 TO 2*d)
  • m$ — four-character month abbreviations, indexed as m$(4*m-3 TO 4*m)
  • n$ — zero-padded two-digit numbers “00” through “60”, indexed as n$(2*h+1 TO 2*h+2) and similar
  • p$ — nine-character phase name strings, indexed as p$(9*g-8 TO 9*g)

User-Defined Graphics

Lines 1040–1050 load six sets of UDGs (characters “a” through “f”) from two DATA blocks at lines 2000 and 2100. Each UDG set uses four bytes per character read from DATA, with POKE USR "a"+m iterating through eight rows. The UDGs likely render symbolic moon-phase icons (crescent, half, full disc) that appear beside each phase entry via CHR$ (g+143) in the PRINT at line 30, selecting one of the four phase symbols based on g.

Output Channel Handling

The program uses OPEN #4 to direct output either to the screen ("s") or printer ("p"), then consistently uses PRINT #4 throughout. At line 9000, when the computed year yr exceeds the requested year y, the channel is closed with CLOSE #4 and a two-tone beep signals completion. The year-end check at line 10 routes to 9000 (overshoot) or returns early at line 12 (not yet reached), allowing the loop to self-terminate correctly.

Notable Techniques

  • The variable mn tracks the current month and triggers a blank line (PRINT #4) whenever the month changes, grouping output by month.
  • VAL "number" is not used here; GO TO targets are direct line numbers throughout.
  • Line 25 computes the day-of-week using modular arithmetic: d = (z+1) mod 7 + 1, where z is the integer Julian Day.
  • The fractional Julian Day f = jd - INT(jd) is converted to hours and minutes using 24*f and 60*(f-h) for display in t$.
  • Input validation at line 1165 restricts the year to 1000–4000 with a penalty beep on out-of-range entries.
  • The decorative title box at line 1150 uses block graphics characters embedded in string literals, and line 1155 draws a pixel border around the screen using PLOT/DRAW.

Potential Bugs and Anomalies

  • Variables t2 and t3 are computed at line 110 but the actual expressions in lines 120–140 expand t*t and t*t*t inline rather than using t2/t3 in line 120, making t2 and t3 redundant in that line (though they are used correctly in lines 130–140).
  • At line 350, the expression 12*(e>=13.5) uses a Boolean comparison as a multiplier — a valid BASIC idiom where TRUE=1 — to subtract 12 from e when appropriate.
  • The variable c is reused across subroutines (Gregorian correction in 300, trigonometric correction in 150/200), which is safe because each subroutine sets c before use, but it reduces readability.

Content

Appears On

Predict eclipses across four millennia, track planetary positions through five centuries, calculate loan amortization schedules, or encode secret messages with modular arithmetic — Imre Auersbacher's collection brings scientific precision and practical utility to the TS 2068.

Related Products

Related Articles

Related Content

Image Gallery

Source Code

    2 REM  Moon Phase Calculator 
    4 REM  \* 1985 I. Auersbacher 
    8 BORDER 5: GO TO 1000
   10 IF yr>y THEN GO TO 9000
   12 IF yr<y THEN RETURN 
   15 LET f=24*f: LET h=INT f
   20 LET n=INT (60*(f-h)): IF m>mn THEN PRINT #4: LET mn=m
   25 LET t$=n$(2*h+1 TO 2*h+2)+":"+n$(2*n+1 TO 2*n+2): LET d=z+1.0: LET d=d-(7*INT (d/7))+1
   30 PRINT #4;CHR$ (g+143);" ";p$(9*g-8 TO 9*g);d$(2*d-1 TO 2*d);" ";m$(4*m-3 TO 4*m);n$(2*dy+1 TO 2*dy+2);",";yr;"  ";t$
   35 RETURN 
   50 BEEP 0.05,22: LET j=(y-1900)*12.3685: LET j=INT j: LET mn=1
   52 PRINT #4;"Moon Phase ";TAB 11;" Date of Event ";TAB 26;" Time ": PRINT #4;"\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''":
   55 LET k=j: LET g=1: GO SUB 100: GO SUB 150: GO SUB 300: GO SUB 10: LET k=j+0.25: LET g=2
   60 GO SUB 100: GO SUB 200: GO SUB 300: GO SUB 10: LET k=j+0.5: LET g=3: GO SUB 100: GO SUB 150
   65 GO SUB 300: GO SUB 10: LET k=j+0.75: LET g=4: GO SUB 100: GO SUB 200: GO SUB 300: GO SUB 10
   70 LET j=j+1: GO TO 55
  100 LET t=k/1236.85
  110 LET t2=t*t: LET t3=t*t*t
  120 LET jd=2415020.75933+29.53058868*k+(0.0001178*t*t-1.55e-7*t*t*t+0.00033*SIN (2.90702+2.31902*t-1.601e-4*t*t))
  130 LET m=6.269645+5.079842936e-1*k-5.81195e-7*t2-6.05629e-8*t3
  135 LET n=5.341149+6.733775529*k+1.872843e-4*t2+2.157227e-7*t3
  140 LET f=0.3716923+6.818486627*k-2.88468e-5*t2-4.1713e-8*t3
  145 RETURN 
  150 LET c=(.1734-.000393*t)*SIN m+0.0021*SIN (2*m)-0.4068*SIN n+0.0161*SIN (2*n)-0.0004*SIN (3*n)+0.0104*SIN (2*f)-0.0051*SIN (m+n)-0.0074*SIN (m-n)+0.0004*SIN (2*f+m)-0.0004*SIN (2*f-m)-0.0006*SIN (2*f+n)+0.0010*SIN (2*f-n)+0.0005*SIN (m+2*n)
  160 LET jd=jd+c+0.5: RETURN 
  200 LET c=(0.1721-0.0004*t)*SIN m+0.0021*SIN (2*m)-0.628*SIN n+0.0089*SIN (2*n)-0.0004*SIN (3*n)+0.0079*SIN (2*f)-0.0119*SIN (m+n)-0.0047*SIN (m-n)+0.0003*SIN (2*f+m)-0.0004*SIN (2*f-m)-0.0006*SIN (2*f+n)+0.0021*SIN (2*f-n)+0.0003*SIN (m+2*n)+0.0004*SIN (m-2*n)-0.0003*SIN (2*m+n)
  210 IF g=2 THEN LET c=c+0.0028-0.0004*COS m+0.0003*COS n
  220 IF g=4 THEN LET c=c-0.0028+0.0004*COS m-0.0003*COS n
  230 LET jd=jd+c+0.5: RETURN 
  300 LET z=INT jd: LET f=jd-z
  310 IF z<2299161 THEN LET a=z
  320 IF z>=2299161 THEN LET a=INT ((z-1867216.25)/36524.25): LET a=z+1+a-INT (a/4)
  330 LET b=a+1524: LET c=INT ((b-122.1)/365.25): LET d=INT (365.25*c): LET e=INT ((b-d)/30.6001)
  340 LET dy=b-d-INT (30.6001*e)
  350 LET m=e-1-12*(e>=13.5)
  360 LET yr=c-4716+1*(m<2.5)
  370 RETURN 
 1000 LET d$="SuMoTuWeThFrSa"
 1010 LET m$="Jan.Feb.Mar.Apr.May Jun.Jul.Aug.Sep.Oct.Nov.Dec."
 1020 LET n$="00010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960"
 1025 LET p$="New Moon 1st. Qtr Full Mn. Last Qtr   "
 1030 BEEP 0.05,22: BEEP 0.06,20: POKE 23609,10: RESTORE 2000
 1040 FOR m=0 TO 7: READ n,f,t,c: POKE USR "a"+m,n: POKE USR "b"+m,f: POKE USR "c"+m,t: POKE USR "d"+m,c: NEXT m
 1050 RESTORE 2100: FOR m=0 TO 7: READ n,f: POKE USR "e"+m,n: POKE USR "f"+m,f: NEXT m
 1100 BORDER 5: PAPER 3: CLS 
 1150 PRINT PAPER 6;AT 2,3;"\:'\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\''\':";AT 3,3;"\:  Moon Phase Calculator  \ :";AT 4,3;"\:                         \ :";AT 5,3;"\:  \* 1985 I. Auersbacher  \ :";AT 6,3;"\:.\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\.:"
 1155 PLOT 0,0: DRAW 0,175: DRAW 255,0: DRAW 0,-175: DRAW -255,0
 1160 PRINT PAPER 7;AT 8,4;"Enter Year:";
 1165 INPUT y: IF y<1000 OR y>4000 THEN BEEP 1,-20: GO TO 1165
 1170 PRINT PAPER 6;" ";y;" "
 1180 PAUSE 30: PRINT PAPER 6;AT 10,4;"Output to which device? "
 1190 PRINT PAPER 7;AT 12,9;"1-TV Screen ";AT 13,9;"2-TS Printer"
 1195 PAUSE 30: PRINT PAPER 6;AT 15,4;"Please pick option (1-2)"
 1200 LET q$=INKEY$: IF q$="" THEN GO TO 1200
 1210 LET t=CODE q$-48: IF (t<1)+(t>2) THEN BEEP 0.5,-15: BEEP 0.6,-20: GO TO 1200
 1220 BEEP .05,22: PRINT INK 0;AT 11+t,6;CHR$ 148; INK 6;CHR$ 149
 1230 PAUSE 70: IF t=1 THEN OPEN #4,"s": PAPER 7: CLS : GO TO 50
 1300 OPEN #4,"p": PRINT FLASH 1; PAPER 7;AT 18,4;" See printer for output ": GO TO 50
 2000 DATA 0,60,0,60,60,98,60,70,126,241,66,143,126,241,66,143,126,241,66,143,126,241,66,143,60,98,60,70,0,60,0,60
 2100 DATA 0,24,0,48,127,96,127,255,127,255,115,248,115,248,127,240
 3000 SAVE "moon" LINE 8: STOP 
 9000 LPRINT : LPRINT : LPRINT : CLOSE #4: BEEP .2,25: BEEP .2,20

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

Scroll to Top