Converts Gregorian calendar and Julian dates. Based on a TI-59 program by Charles Kluepfel.
This program converts dates between the Gregorian calendar and Julian Day Numbers, a continuous count of days used in astronomy. It accepts input in either direction: a calendar date (month, day, year, and AD/BC era) to its Julian Day Number, or a Julian Day Number back to a calendar date. The Gregorian-to-Julian conversion handles the BC/AD era transition by negating and shifting the year, and corrects for century leap-year irregularities using the standard INT(Y/100) adjustment. A shared subroutine at line 4000 performs the repeated division-with-remainder operations needed during the reverse (JD-to-date) conversion. The day-of-week calculation uses a fractional-part trick on (JD+1)/7 to map the Julian Day Number to a named weekday.
Program Structure
The program is divided into clearly labelled sections using REM blocks. Control flow is menu-driven from line 110, branching to one of two main routines:
- Lines 1000–2230: Gregorian date → Julian Day Number, followed by day-of-week display, then looping back to line 1000.
- Lines 3000–3170: Julian Day Number → Gregorian date, looping back to line 3000.
- Lines 4000–4090: Shared subroutine used three times during JD-to-date conversion.
Both main routines loop indefinitely (GO TO 1000 at line 2230, GO TO 3000 at line 3170), requiring a BREAK to exit. There is no unified main loop or return-to-menu option after either calculation path is entered.
Gregorian-to-Julian Conversion (Lines 2000–2150)
The algorithm follows the standard astronomical formula, ported from a TI-59 program by Charles Kluepfel (1978). Key steps:
- Months January and February are treated as months 13 and 14 of the previous year (lines 2015–2020), a standard technique that simplifies the 30.6-day month-length formula.
- For BC years, the astronomical year numbering convention is applied at line 1045:
Y = -(Y-1), mapping 1 BC → 0, 2 BC → −1, etc. - Negative years trigger a 400-year block alignment at lines 2055–2070, accumulating a correction in
Jand shiftingYinto a non-negative range before the main formula runs. - The Gregorian century correction is
INT(Y/100)scaled by 0.75 and subtracted at line 2130, implementing the standard-INT(A/100)+INT(A/400)+2correction folded into the constant 1721060.
A notable oddity is the use of DIS at lines 2140–2150: it is set to JD (which is 0 at this point), then JD is set to J, and DIS = J - 0, so the display value always equals J. This appears to be a vestige of a more general accumulation pattern from the original calculator program.
Julian-Day-to-Gregorian Conversion (Lines 3000–3170)
This section calls the subroutine at line 4000 three times to successively extract the year century, year within century, and month. The logic relies on a shared register protocol using T, DIS, XT, and SAVE:
| Call | DIS (divisor) | Purpose |
|---|---|---|
| 1st (line 3030) | 36524.25 | Extract century count → contributes to Y |
| 2nd (line 3060) | 365.25 | Extract year within century → adds to Y |
| 3rd (line 3105) | 30.6 | Extract month number → sets M |
After the third call, a swap at line 3120 puts the day remainder into DIS and D = DIS + 1 at line 3130. The month adjustment for January/February (adding back the 12 offset) is at lines 3140–3150, and BC conversion at line 3155 using ABS Y + 1.
Shared Subroutine (Lines 4000–4090)
The subroutine performs an integer division of T by DIS, returning the quotient in J and the remainder (scaled back to the original units) in T. It uses a swap idiom with XT as a temporary register since the platform lacks multi-variable swap syntax. Key steps:
- Line 4010: Swaps
DISandT; saves originalDISintoJand pre-computesSAVE = DIS + 0.9. - Lines 4030–4032: Computes
DIS = INT((DIS+0.9)/T), with a correction+1if negative before truncation — handling negative-year edge cases. - Line 4050: Computes remainder as
SAVE - quotient * original_divisor. - Lines 4070–4071: Applies the same negative-integer floor correction to the remainder
T.
The +0.9 bias before INT is used in place of rounding, since the inputs are not exact integers due to floating-point intermediate values.
Day-of-Week Calculation
Lines 2210–2227 use a fractional-part technique: (JD+1)/7 - INT((JD+1)/7) gives the fractional day position within a week cycle, then INT(7*frac + 1.5) maps it to an integer 1–7. Seven consecutive IF statements print the named weekday. This is slightly inefficient but clear; a DATA/array approach was not available in standard Sinclair BASIC of this era.
Notable Bugs and Anomalies
- Line 20’s
REMsays “CALENDER” (misspelling of “calendar”) — a cosmetic issue only. - The variable
SAVEused in the subroutine (line 4010) is not declared in the variable list in theREMat lines 30–31, suggesting it was added during porting. - The menu at line 110 does not validate input beyond checking for 0 or 1; any other value causes the program to fall through both
IFchecks and re-display thePRINT ATline from line 100, effectively looping but without re-prompting cleanly. - Line 3080 adds 91.4 to
T, which is a fixed offset used in month extraction; this is a direct translation of the TI-59 register arithmetic and works correctly but is not self-documenting. - The
© = RESETkeyword in the titleREMat line 10 is the TS2068RESETtoken, used here as part of the copyright symbol in the author credit — a coincidence of character encoding.
Content
Source Code
10 REM "JULIAN DAY" © by Beb H.Jackson, 1984; ALL RIGHTS RESERVED
20 REM -- CONVERTS GREGORIAN CALENDER & JULIAN DAY
25 REM SOURCE-- TI-59 PROGRAM "JULIAN DAY NUMBER CALENDER" BY CHARLES KLUEPFEL 2/23/78
30 REM VARIABLES-- M-- MONTH D-- DATE Y-- YEAR E$-- ERA [AD or BC] JD--JULIAN DAY J-- JULIAN ACCUM
31 REM DIS--DISPLAY REG WD--WEEK DAY[1=SUN] F-- MENU FLAG WR--WORKING REG XT--DISPLAY<>TEST REG T -- TEST REGISTER
100 PRINT AT 1,5;"JULIAN DAY PROGRAM"
110 INPUT "DATE TO JD: 0 JD TO DATE: 1 CHOICE=";F
120 IF F=0 THEN GO TO 1000
130 IF F=1 THEN GO TO 3000
1000 INPUT "MONTH [1 TO 12]=";M
1005 PRINT "MONTH=";M
1010 INPUT "DATE [1 TO 31]=";D
1015 PRINT "DATE=";D
1020 INPUT "YEAR [XXXX]=";Y
1030 INPUT "[ AD or BC ]=";E$
1035 IF E$<>"AD" AND E$<>"BC" THEN GO TO 1030
1040 PRINT "YEAR=";Y;" ";E$
1045 IF E$="BC" THEN LET Y=-1*( Y-1)
2000 REM --GREG TO JULIAN
2010 LET J=0: LET JD=0
2015 IF (M-3)>=0 THEN GO TO 2050
2017 LET Y=Y-1
2020 LET M=M+12
2050 IF Y>=0 THEN GO TO 2100
2055 LET J=146097
2060 LET J=J*((INT (Y/400))-1)
2070 LET Y=Y-400*((INT (Y/400))-1)
2100 LET J=J+D
2110 LET J=J+INT (30.6*M-32.4)
2120 LET J=J+INT (365.25*Y)
2130 LET J=J+1721060-INT (.8+.75*INT (Y/100))
2140 LET DIS=JD
2145 LET JD=J
2150 LET DIS=J-DIS
2160 PRINT "JULIAN DAY=";DIS
2200 REM --DAY OF WEEK
2210 LET DIS=(JD+1)/7-INT ((JD+1)/7)
2220 LET WD=INT (7*DIS+1.5)
2221 IF WD=1 THEN PRINT "SUNDAY"
2222 IF WD=2 THEN PRINT "MONDAY"
2223 IF WD=3 THEN PRINT "TUESDAY"
2224 IF WD=4 THEN PRINT "WEDNESDAY"
2225 IF WD=5 THEN PRINT "THURSDAY"
2226 IF WD=6 THEN PRINT "FRIDAY"
2227 IF WD=7 THEN PRINT "SATURDAY"
2230 GO TO 1000
3000 REM --JULIAN DAY TO GREG
3005 INPUT "JULIAN DAY=";JD
3007 PRINT "JD=";JD
3010 LET T=JD+32045-1
3020 LET DIS=36524.25
3030 GO SUB 4000
3040 LET Y=100*DIS-4800
3050 LET DIS=365.25
3060 GO SUB 4000
3070 LET Y=Y+DIS
3080 LET T=T+91.4
3090 LET DIS=30.6
3105 GO SUB 4000
3110 LET M=DIS
3120 LET XT=DIS: LET DIS=T: LET T=XT
3130 LET D=DIS+1
3140 IF M<13 THEN GO TO 3154
3150 LET Y=Y+1: LET M=M-12
3154 LET E$="AD"
3155 IF Y<=0 THEN LET Y=ABS Y+1: LET E$="BC"
3160 PRINT M;"-";D;"-";Y;" ";E$
3170 GO TO 3000
4000 REM --JD TO GREG SBR
4010 LET XT=DIS: LET DIS=T: LET T=XT: LET J=T: LET SAVE=DIS+.9
4030 LET DIS=((DIS+.9)/T)
4031 IF DIS<0 THEN LET DIS=DIS+1
4032 LET DIS=INT DIS
4040 LET WR=DIS: LET DIS=J: LET J=WR
4050 LET DIS=-1*WR*DIS+SAVE
4060 LET XT=DIS: LET DIS=T: LET T=XT
4070 IF T<0 THEN LET T=T+1
4071 LET T=INT T
4080 LET DIS=J
4090 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

