In the summer of 1999 I reread The Lord of the Rings for perhaps the dozenth time. With that particular reading I studied, really studied, Appendix D on the calendrical systems in use in Middle-Earth in the Third Age. I was drawn, in particular, to the Hobbit calendar and decided to write a quick-and-dirty computer program to convert our dates into Hobbit dates.
Today, November 20th, is in Shire Reckoning, the first of Foreyule.
What made me think of this, today, of all days? Maybe it’s playing The Third Age, EA’s Lord of the Rings turn-based RPG on the XBox. How is the game? I’ll save that for another post.
But for those who want to see the program, after the cut is the BASIC source code. Yes, I wrote it in BASIC. You have a problem with that?
110 GOSUB 1000
120 GOSUB 2000
130 GOSUB 2500
140 REM PRINT “JULIAN DATE”; JL
150 REM PRINT “SHIRE JULIAN DATE”; SJ
160 GOSUB 3000
170 GOSUB 3500
180 GOSUB 4000
190 GOSUB 4500
200 PRINT “Your date is “;W$;”, “;D$
210 REM PRINT DT
1000 REM Input date
1010 PRINT “Year”;
1020 INPUT Y:Y=INT(Y)
1030 IF Y<0 THEN GOTO 1010
1040 GOSUB 1500
1050 PRINT “Month”;
1060 INPUT M:M=INT(M)
1070 IF M<1 OR M>12 THEN GOTO 1050
1080 PRINT “Day”;
1090 INPUT D:D=INT(D)
1100 IF D<1 THEN GOTO 1080
1110 IF M=2 AND D>28+LP THEN GOTO 1080
1120 IF (M=4 OR M=6 OR M=9 OR M=11) AND D>30 THEN GOTO 1080
1130 IF M>31 THEN GOTO 1080
1500 REM Leap Year Check
1520 IF Y/4=INT(Y/4) THEN LP=1
1530 IF Y/100=INT(Y/100) THEN LP=0
1540 IF Y/400=INT(Y/400) THEN LP=1
2000 REM Julian Date conversion
2020 IF M=2 THEN JL=31
2030 IF M=3 THEN JL=59
2040 IF M=4 THEN JL=90
2050 IF M=5 THEN JL=120
2060 IF M=6 THEN JL=151
2070 IF M=7 THEN JL=181
2080 IF M=8 THEN JL=212
2090 IF M=9 THEN JL=243
2100 IF M=10 THEN JL=273
2110 IF M=11 THEN JL=304
2120 IF M=12 THEN JL=334
2140 IF M>2 THEN JL=JL+LP
2500 REM Shire Julian Date conversion
2530 IF SJ>365+LP THEN SJ=SJ-(365+LP)
3000 REM Shire Date calculation
3020 IF SJ=1 THEN SD=2:SM=13:RETURN
3030 IF SJ=182 THEN SD=1:SM=14:RETURN
3040 IF SJ=183 THEN SM=15:RETURN
3050 IF SJ=184+LP THEN SD=2:SM=14:RETURN
3060 IF SJ=184 AND LP=1 THEN SM=16:RETURN
3070 IF SJ=365+LP THEN SD=1:SM=13:RETURN
3090 IF SJ>182+LP THEN SJ=SJ-(3+LP)
3500 REM Shire month string
3510 IF SM=1 THEN M$=”Afteryule”
3520 IF SM=2 THEN M$=”Solmath”
3530 IF SM=3 THEN M$=”Rethe”
3540 IF SM=4 THEN M$=”Astron”
3550 IF SM=5 THEN M$=”Thrimidge”
3560 IF SM=6 THEN M$=”Forelithe”
3570 IF SM=7 THEN M$=”Afterlithe”
3580 IF SM=8 THEN M$=”Wedmath”
3590 IF SM=9 THEN M$=”Halimath”
3600 IF SM=10 THEN M$=”Winterfilth”
3610 IF SM=11 THEN M$=”Blotmath”
3620 IF SM=12 THEN M$=”Foreyule”
3630 IF SM=13 THEN M$=”Yule”
3640 IF SM=14 THEN M$=”Lithe”
3650 IF SM=15 THEN M$=”Midyear’s Day”
3660 IF SM=16 THEN M$=”Overlithe”
4000 REM Create date string
4020 IF SM>14 THEN D$=M$:RETURN
4030 D$=STR$(SD)+” “+M$
4500 REM Shire day of week calculation
4510 GOSUB 2500
4530 IF SJ=183 OR (SJ=184 AND LP=1) THEN DT=8:RETURN
4535 IF SJ>183 THEN SJ=SJ-LP-1
4550 IF DT=0 THEN W$=”Highday”
4560 IF DT=1 THEN W$=”Sterday”
4570 IF DT=2 THEN W$=”Sunday”
4580 IF DT=3 THEN W$=”Monday”
4590 IF DT=4 THEN W$=”Trewsday”
4600 IF DT=5 THEN W$=”Hevensday”
4610 IF DT=6 THEN W$=”Mersday”
6 thoughts on “For Geekoid Fanboys Only”
Had a bit of a problem because you have some curly quotes in there, and QBasic isn’t too fond of that. But once I sorted those out with Notepad, I managed to learn that I was born on Hevensday, 18 Afterlithe. Which is somewhat disturbing. “Heaven” and “afterlife”?
Feh. I don’t think I even have QBasic on this machine. So I ported it to C++. Kinda. ‘Cause it doesn’t quite work. And I don’t feel like debugging it right now. 🙂
(BTW, line 1130 ought to be “d>31”. And you called the subroutine starting at 2500 twice, which won’t do anything. :))
Andrew, thank you for the error catch on line 1130. In five years I hadn’t noticed that. Shire.bas is now updated. 🙂
As for the subroutine at line 2500, I disagree strongly that it “won’t do anything.” I admit I’m biased, but I think the subroutine is absolutely vital for accuracy’s sake in the date conversion process.
Let’s examine what it does. The REM comment in line 2500 calls it “Shire Julian Date Conversion.” A cryptic comment, true. The subroutine at line 2000 converts the inputed date into a Julian number, counting forward from the beginning of the year. So, what is the conversion?
Let’s turn to Professor Tolkien. We writes in Appendix D, “It appears that Mid-Year’s Day was intended to correspond as nearly as possible to the summer solstice. In that case Shire Dates were actually in advance of ours by some ten days, and our New Year’s Day corresponded more or less to the Shire January 9.” On that assumption Mid-Year’s Day should be the equivalent of June 21st. I worked backwards from that–I knew what my output should be, and so generated some calculations to generate the pre-determined result–and found that Tolkien was incorrect–the calendars are off by eleven days, not ten.
Looking at the subroutine, line 2510 is pointless, as the variable SJ (Shire Julian) is defined in line 2520 by taking JL (our Julian date) and adding eleven days. Line 2530 then “rolls over” dates at the end of our year to the beginning of the Hobbit year. If you unREMark lines 140 and 150 the program will output the two Julian dates–ours and the Hobbit’s–for comparison’s sake.
Why call the subroutine twice? The simplest explanation–and I’m drawing back five years here–is that the Hobbit calendar has days that fall outside of both weeks and months, hence the need to remove days from the Shire Julian date to simplify both the Hobbit week and month calculations.
I wouldn’t call shire.bas an elegent program. It does what I wanted it to do–take our dates and make a reasonable calculation as to where they would fall on the Hobbit calendar. Which the program does. 🙂
Oh, I realized that the first call did something. It was the second call that I thought wouldn’t do anything–unless JL is changing, which I don’t see it doing after the initial call. *shrug* Then again, my version doesn’t work (albeit for other reasons), and yours does, so you win. 🙂
And you’re right, it’s not elegant–but then, very little BASIC is. 🙂
JL doesn’t change. SJ does change, hence the two calls to subroutine 2500.
The first time the subroutine is called the program pulls out the non-month days in subroutine 3000, subtracting from SJ in lines 3080 and 3090.
The second time the program calls subroutine 2500 occurs later, in subroutine 4500 when the program figures out the day of the week. Because the value for SJ was no longer accurate because of previous calculations, the program recalculates SJ from JL.
I’m trying to remember why I set the program up in such a fashion. I think the day of the week calculation was a late idea, something I hadn’t initially planned upon.
I always meant to rewrite the program in Pascal. One of these days….