Here’s the code for the moon phase calculations included on
my Web pages. This is based on calculations given in the book
Duffett-Smith, Peter. 1988. Practical Astronomy with Your Calculator, 3rd Ed. Cambridge Univ. Press.
Here’s a QBASIC program I wrote that asks the user to supply a date, time, and time zone, then calculates the moon phase for that time. This is simplified from my original code which performed calculations for a three-month period. Since it is based on user input, I tried to include as much error checking as occurred to me. Also, the calculations are cumbersome in places because QBASIC does not do date arithematic.
DIM Months$(12) SCREEN 13: WIDTH 80 'Get the date from the user. Retry: COLOR 1 INPUT "Enter a date in the format mm-dd-yyyy> ", ThisDate$ year = VAL(RIGHT$(ThisDate$, 4)) month = VAL(LEFT$(ThisDate$, 2)) day = VAL(MID$(ThisDate$, 4, 2)) IF year = 0 OR month = 0 OR day = 0 THEN PRINT "You did not enter the date in the proper format." IF year = 0 THEN PRINT "You specified a year of 0." IF month = 0 THEN PRINT "You specified a month of 0." IF day = 0 THEN PRINT "You specified a day of 0." PRINT "Please try again using the format mm-dd-yyyy." GOTO Retry END IF IF year < 1000 OR year > 2500 THEN PRINT "The year you entered was"; year PRINT "That doesn't make sense to me." INPUT "Do you want to continue anyway?", Reply$ Reply$ = LEFT$(Reply$, 1) Reply$ = LCASE$(Reply$) IF Reply$ = "n" THEN CLS GOTO Retry END IF END IF IF day < 1 THEN PRINT "The day you entered was"; day PRINT "That doesn't make sense to me." PRINT "Try again using mm-dd-yyyy format." GOTO Retry END IF LeapCheck = (year - 1980) MOD 4 IF LeapCheck = 0 THEN leap$ = "yes" ELSEIF LeapCheck <> 0 THEN leap$ = "no" END IF SELECT CASE month CASE 1 month$ = "January" IF day > 31 GOTO TooMany CASE 2 month$ = "February" IF leap$ = "yes" AND day > 29 GOTO TooMany IF leap$ = "no" AND day > 28 GOTO TooMany CASE 3 month$ = "March" IF day > 31 GOTO TooMany CASE 4 month$ = "April" IF day > 30 GOTO TooMany CASE 5 month$ = "May" IF day > 31 GOTO TooMany CASE 6 month$ = "June" IF day > 30 GOTO TooMany CASE 7 month$ = "July" IF day > 31 GOTO TooMany CASE 8 month$ = "August" IF day > 31 GOTO TooMany CASE 9 month$ = "September" IF day > 30 GOTO TooMany CASE 10 month$ = "October" IF day > 31 GOTO TooMany CASE 11 month$ = "November" IF day > 30 GOTO TooMany CASE 12 month$ = "December" IF day > 31 GOTO TooMany CASE ELSE month$ = STR$(month) PRINT month$; " is not a valid month." PRINT "Please try again." GOTO Retry END SELECT GOTO Verify TooMany: PRINT "There aren't"; day; "days in "; month$ PRINT "Please try again." GOTO Retry Verify: COLOR 2 PRINT "The day you chose was "; day; month$; year COLOR 3 INPUT "Is this correct? ", Reply$ Reply$ = LEFT$(Reply$, 1) Reply$ = LCASE$(Reply$) IF Reply$ = "n" THEN CLS GOTO Retry END IF 'Get the time from the user. Timetry: COLOR 4 INPUT "Enter a time in the format hh:mm:ss> ", ThisTime$ second = VAL(RIGHT$(ThisTime$, 2)) hour = VAL(LEFT$(ThisTime$, 2)) minute = VAL(MID$(ThisTime$, 4, 2)) IF hour < 0 THEN PRINT "You specified less than 0 hours." PRINT "Try again." GOTO Timetry ELSEIF minute < 0 THEN PRINT "You specified less than 0 minutes." PRINT "Try again." GOTO Timetry ELSEIF second < 0 THEN PRINT "You specified less than 0 seconds." PRINT "Try again." GOTO Timetry ELSEIF second > 60 THEN PRINT "You specified more than 60 seconds." PRINT "Try again." GOTO Timetry ELSEIF minute > 60 THEN PRINT "You specified more than 60 minutes." PRINT "Try again." GOTO Timetry ELSEIF hour > 24 THEN PRINT "You specified more than 24 hours." PRINT "Try again." GOTO Timetry END IF TimeOfDay: COLOR 5 INPUT "Is this AM or PM?", ampm$ ampm$ = LEFT$(ampm$, 1) ampm$ = LCASE$(ampm$) IF ampm$ = "a" OR ampm$ = "p" THEN GOTO FixIt GOTO TimeOfDay FixIt: IF ampm$ = "p" AND hour < 12 THEN hour = hour + 12 IF ampm$ = "a" AND hour > 12 THEN hour = hour - 12 COLOR 6 PRINT "The time you chose is"; hour; ":"; minute; ":"; second; ampm$ COLOR 7 INPUT "Is this correct? ", Reply$ Reply$ = LEFT$(Reply$, 1) Reply$ = LCASE$(Reply$) IF Reply$ = "n" THEN CLS GOTO Timetry END IF ' correct to GMT TimeZone: COLOR 9 PRINT "Choose a Time Zone:" COLOR 10 PRINT "5. Eastern Standard Time" COLOR 11 PRINT "4. Eastern Daylight Time" COLOR 12 PRINT "6. Central Standard Time" COLOR 13 PRINT "5. Central Daylight Time" COLOR 14 PRINT "0. Greenwich Mean Time" COLOR 15 INPUT "Pick a number corresponding to a time zone. ", choice uthour = hour + choice IF uthour >= 24 THEN uthour = uthour - 24 IF uthour < 12 THEN ampm$ = "a" day = day + 1 END IF IF day > 31 AND month = 1 THEN month = 2 month$ = "February" day = 1 ELSEIF day > 29 AND month = 2 AND leap$ = "yes" THEN month = 3 month$ = "March" day = 1 ELSEIF day > 28 AND month = 2 AND leap$ = "no" THEN month = 3 month$ = "March" day = 1 ELSEIF day > 31 AND month = 3 THEN month = 4 month$ = "April" day = 1 ELSEIF day > 30 AND month = 4 THEN month = 5 month$ = "May" day = 1 ELSEIF day > 31 AND month = 5 THEN month = 6 month$ = "June" day = 1 ELSEIF day > 30 AND month = 6 THEN month = 7 month$ = "July" day = 1 ELSEIF day > 31 AND month = 7 THEN month = 8 month$ = "August" day = 1 ELSEIF day > 31 AND month = 8 THEN month = 9 month$ = "September" day = 1 ELSEIF day > 30 AND month = 9 THEN month = 10 month$ = "October" day = 1 ELSEIF day > 31 AND month = 10 THEN month = 11 month$ = "November" day = 1 ELSEIF day > 30 AND month = 11 THEN month = 12 month$ = "December" day = 1 ELSEIF day > 31 AND month = 12 THEN month = 1 month$ = "January" day = 1 year = year + 1 END IF COLOR 2 PRINT "The date and time you chose was "; day; month$; year; uthour; ":"; minute; ":"; second; ampm$; " UT" NumHrs = uthour + (minute + (second / 60)) / 60 'Calculate number of days since beginning of the specified year. IF month > 2 GOTO No8 'no 3-2 DayNo = month - 1 'no 3-3 IF leap$ = "no" THEN 'no 3-4 DayNo = DayNo * 63 ELSEIF leap$ = "yes" THEN DayNo = DayNo * 62 END IF DayNo = DayNo \ 2 'no 3-5&6 GOTO No12 'no 3-7 No8: DayNo = (month + 1) * 30.6 'no 3-8&9 DayNo = INT(DayNo) 'no 3-10 IF leap$ = "no" THEN 'no 3-11 DayNo = DayNo - 63 ELSEIF leap$ = "yes" THEN DayNo = DayNo - 62 END IF No12: DayNo = DayNo + day 'no 3-12 DayNo = DayNo + NumHrs / 24 'PRINT "This is"; DayNo; "days into the year." OtherDays = (year - 1990) * 365 leapdays = INT((year - 1989) / 4) D = OtherDays + leapdays 'no 46-1 'PRINT "Days from Jan. 1 of current year to 0-0-90 is "; D D = D + DayNo 'no 46-2 'PRINT "Total days from then is "; D NoOfDays = D + nCounter / 2 N = NoOfDays * (360 / 365.242191#) 'no 46-3 N = ABS(N) - INT(ABS(N / 360)) * 360 'no 46-3 Mo = N + 279.403303# - 282.768422# 'no 46-4 IF Mo < 0 THEN Mo = Mo + 360 'no 46-4 Ec = 360 * .016713 * SIN(Mo * 3.141592654# / 180) / 3.141592654# 'no 46-5 lamda = N + Ec + 279.403303# 'no 46-6 IF lamda > 360 THEN lamda = lamda - 360 'no 46-6 'PRINT "N", "Mo", "Ec", "Lamda" 'PRINT N, Mo, Ec, lamda l = 13.1763966# * NoOfDays + 318.351648# 'no 65-4 l = ABS(l) - INT(ABS(l / 360)) * 360 'no 65-4 Mm = l - .1114041 * D - 36.34041# 'no 65-5 Mm = ABS(Mm) - INT(ABS(Mm / 360)) * 360 'no 65-5 N65 = 318.510107# - .0529539 * NoOfDays 'no 65-6 N65 = ABS(N65) - INT(ABS(N65 / 360)) * 360 'no 65-6 Ev = 1.2739 * SIN((2 * (1 - lamda) - Mm) * 3.141592654# / 180) 'no 65-7 'PRINT "l", "Mm", "N65", "Ev" 'PRINT l, Mm, N65, Ev Ae = .1858 * SIN(Mo * 3.141592654# / 180) 'no 65-8 A3 = .37 * SIN(Mo * 3.141592654# / 180) 'no 65-8 Mmp = Mm + Ev - Ae - A3 'no 65-9 Ec = 6.2886 * SIN(Mmp * 3.141592654# / 180) 'no 65-10 'PRINT "Ae", "A3", "Mmp", "Ec" 'PRINT Ae, A3, Mmp, Ec A4 = .214 * SIN((2 * Mmp) * 3.141592654# / 180) 'no 65-11 lp = l + Ev + Ec - Ae + A4 'no 65-12 V = .6583 * SIN((2 * (lp - lamda)) * 3.141592654# / 180) 'no 65-13 lpp = lp + V 'no 65-14 'PRINT "A4", "lp", "V", "lpp" 'PRINT A4, lp, V, lpp D67 = lpp - lamda 'no 67-2 F = .5 * (1 - COS(D67 * 3.141592654# / 180)) 'no 67-3 'PRINT "D67", "F" 'PRINT D67, F x = (SIN(D67 * 3.141592654# / 180)) 'variables created include: NoOfDays, F, x IF F < .01 OR (F > .45 AND F < .55) OR F > .98 THEN SELECT CASE F CASE IS < .003 Phase$ = "New" MoonDate = NoOfDays GOTO GotIt CASE .47 TO .53 IF SGN(x) > 0 THEN Phase$ = "First Quarter" IF SGN(x) < 0 THEN Phase$ = "Last Quarter" MoonDate = NoOfDays GOTO GotIt CASE IS > .997 Phase$ = "Full" MoonDate = NoOfDays GOTO GotIt END SELECT END IF 'variables created include Phase$, MoonDate=NoOfDays GotIt: Months$(1) = "Jan" Months$(2) = "Feb" Months$(3) = "Mar" Months$(4) = "Apr" Months$(5) = "May" Months$(6) = "Jun" Months$(7) = "Jul" Months$(8) = "Aug" Months$(9) = "Sep" Months$(10) = "Oct" Months$(11) = "Nov" Months$(12) = "Dec" MoonDate = MoonDate - D - (choice / 24) 'recalc date from start of loop - ut correction MoonDate = MoonDate + day MoonDate = ((MoonDate * 100) \ 10) / 10 TxtMonth$ = Months$(month) IF MoonDate > 31 AND (month = 1 OR month = 3 OR month = 5 OR month = 7 OR month = 8 OR month = 10 OR month = 12) THEN MoonDate = MoonDate - 31 TxtMonth$ = Months$(month) ELSEIF MoonDate > 28 AND month = 2 AND leap$ = "no" THEN MoonDate = MoonDate - 28 TxtMonth$ = Months$(month) ELSEIF MoonDate > 29 AND month = 2 AND leap$ = "yes" THEN MoonDate = MoonDate - 29 TxtMonth$ = Months$(month) ELSEIF MoonDate > 30 AND (month = 4 OR month = 6 OR month = 9 OR month = 11) THEN MoonDate = MoonDate - 30 TxtMonth$ = Months$(month) END IF IF MoonDate > INT(MoonDate + .5) THEN MoonDate = INT(MoonDate) ELSE MoonDate = INT(MoonDate + .5) END IF COLOR 3 PRINT "Phase", "Date" COLOR 4 PRINT Phase$, MoonDate; " "; TxtMonth$; " "; year COLOR 5 |
This code was eventually “translated” into JavaScript, again performing calculations for a three-month period. Since JavaScript has some built-in date functions, the date arithematic was easier. Again, here is a simplified version of the code that grabs the user’s system time and calculates the moon phase from that. In my original version, I included the option for user input, thus considerable error checking (similar to the above) was included. Since this version does not allow for user input, but works from the system time, all that error checking (is it really a valid date?) has not been included. These calculations have subsequently been updated to compensate for browser Y2K bugs and a slight error in the former calculations.
today = new Date(); // initialize to current date hh = today.getHours(); // goes from 0 to 23 var ampm = "am" var NoLoops = hh // this variable is also used for the cuckoo clock if(hh == 0) { NoLoops = 12}; if(hh > 12) { NoLoops = hh - 12; ampm = "pm" } if(hh == 12) { ampm = "pm" } var dd = today.getDate(); var mm = today.getMonth() + 1; // Jan is 0, Feb is 1, etc., hence the +1 var dow = today.getDay(); MonNames = new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"); var ThisMonth = MonNames[mm]; // var yy = today.getYear(); // browser Y2K bug fix -- convert from msec to years because getYear() doesn't work right var millisec = today.getTime(); // this gives msecs var yy = ((((millisec / 1000) / 3600) / 24) / 365.25); yy = Math.floor(yy); yy +=1970; var txtDate = "" + ((dd < 10) ? "0" : "") + dd; // add 0 if less than 10 so displays right txtDate += " " + ThisMonth; txtDate += " " + yy; var mn = today.getMinutes(); // goes from 0 to 59 var txtTime = "" + ((NoLoops < 10) ? "0" : "") + NoLoops; txtTime += ((mn<10) ? ":0" : ":") + mn; // here's where the calculations from the book start var moondate = today; tzone = moondate.getTimezoneOffset() / 60 // in min so convert to hours var moonmsec = moondate.getTime(); // this gives msecs GMtime = moonmsec + (tzone * 60 * 60 * 1000) // GMT in msec // adapted from my VB code var startDate = new Date(89, 11, 31, 00, 00, 00); // equivalent of the book's 0 Jan 90 var startMsec = startDate.getTime(); var dmsec = GMtime - startMsec; D = ((((dmsec /1000) /60) /60) /24); var n = D * (360 / 365.242191); //no 46-3 if (n > 0) { n = n - Math.floor(Math.abs(n / 360)) * 360; //no 46-3 } else { n = n + (360 + Math.floor(Math.abs(n / 360)) * 360); //no 46-3 } var Mo = n + 279.403303 - 282.768422; //no 46-4; if(Mo < 0) { Mo = Mo + 360 } //no 46-4 var Ec = 360 * .016713 * Math.sin(Mo * 3.141592654 / 180) / 3.141592654; //no 46-5 var lamda = n + Ec + 279.403303; //no 46-6 if(lamda > 360) { lamda = lamda - 360 } //no 46-6 var l = 13.1763966 * D + 318.351648; //no 65-4 if (l > 0) { l = l - Math.floor(Math.abs(l / 360)) * 360; //no 65-4 } else { l = l + (360 + Math.floor(Math.abs(l / 360)) * 360); //no 65-4 } var Mm = l - .1114041 * D - 36.34041; //no 65-5 if (Mm > 0) { Mm = Mm - Math.floor(Math.abs(Mm / 360)) * 360; //no 65-5 } else { Mm = Mm + (360 + Math.floor(Math.abs(Mm / 360)) * 360); //no 65-5 } var N65 = 318.510107 - .0529539 * D; //no 65-6 if (N65 > 0) { N65 = N65 - Math.floor(Math.abs(N65 / 360)) * 360; //no 65-6 } else { N65 = N65 + (360 + Math.floor(Math.abs(N65 / 360)) * 360); //no 65-6 } var Ev = 1.2739 * Math.sin((2 * (l - lamda) - Mm) * 3.141592654 / 180); //no 65-7 var Ae = .1858 * Math.sin(Mo * 3.141592654 / 180); //no 65-8 var A3 = .37 * Math.sin(Mo * 3.141592654 / 180); //no 65-8 var Mmp = Mm + Ev - Ae - A3; //no 65-9 var Ec = 6.2886 * Math.sin(Mmp * 3.141592654 / 180); //no 65-10 var A4 = .214 * Math.sin((2 * Mmp) * 3.141592654 / 180); //no 65-11 var lp = l + Ev + Ec - Ae + A4; //no 65-12 var V = .6583 * Math.sin((2 * (lp - lamda)) * 3.141592654 / 180); //no 65-13 var lpp = lp + V; //no 65-14 var D67 = lpp - lamda; //no 67-2 Ff = .5 * (1 - Math.cos(D67 * 3.141592654 / 180)); //no 67-3 Xx = (Math.sin(D67 * 3.141592654 / 180)); // figure out what phase the moon is in and what icon to use to go with it var MoonPhaseMsg = "Just for fun, the moon is "; if(Ff < .02) { document.write ('<IMG name="moonpic" SRC="graphics/steincarter/moon/moon01.gif" HEIGHT="32" WIDTH="32" ALIGN="right" alt="">'); MoonPhaseMsg += "new." } if((Ff > .45) && (Ff < .55) && (Xx > 0)) { document.write ('<IMG name="moonpic" SRC="graphics/steincarter/moon/moon03.gif" HEIGHT="32" WIDTH="32" ALIGN="right" alt="">'); MoonPhaseMsg += "first quarter." } if((Ff > .45) && (Ff < .55) && (Xx < 0)) { document.write ('<IMG name="moonpic" SRC="graphics/steincarter/moon/moon07.gif" HEIGHT="32" WIDTH="32" ALIGN="right" alt="">'); MoonPhaseMsg += "last quarter." } if(Ff > .98) { document.write ('<IMG name="moonpic" SRC="graphics/steincarter/moon/moon05.gif" HEIGHT="32" WIDTH="32" ALIGN="right" alt="">'); MoonPhaseMsg += "full." } if((Ff > .02) && (Ff < .45) && (Xx > 0)) { document.write ('<IMG name="moonpic" SRC="graphics/steincarter/moon/moon02.gif" HEIGHT="32" WIDTH="32" ALIGN="right" alt="">'); MoonPhaseMsg += "waxing." } if((Ff > .02) && (Ff < .45) && (Xx < 0)) { document.write ('<IMG name="moonpic" SRC="graphics/steincarter/moon/moon08.gif" HEIGHT="32" WIDTH="32" ALIGN="right" alt="">'); MoonPhaseMsg += "waning." } if((Ff > .55) && (Ff < .98) && (Xx > 0)) { document.write ('<IMG name="moonpic" SRC="graphics/steincarter/moon/moon04.gif" HEIGHT="32" WIDTH="32" ALIGN="right" alt="">'); MoonPhaseMsg += "waxing gibbous." } if((Ff > .55) && (Ff < .98) && (Xx < 0)) { document.write ('<IMG name="moonpic" SRC="graphics/steincarter/moon/moon06.gif" HEIGHT="32" WIDTH="32" ALIGN="right" alt="">'); MoonPhaseMsg += "waning gibbous." } document.write (MoonPhaseMsg); document.write (' The moon phase calculations are based on your computer reporting that is is'); document.write (" " + txtTime + " " + ampm + " on " + txtDate + ",\n"); document.write (' and that you are ' + tzone + ' hours from GMT.'); |
Here is the JavaScript code in action:
If you’re using Netscape, the time zone offset is properly
reported, but if you're using IE, the time zone offset is reported in
negative numbers (however, the calculations still appear to work OK). For
comparison, EST is +5 hours and EDT is +4 hours. From some information I
found on the Web a couple years ago, if your computer is incorrectly
reporting your time zone (they tend to think they’re in Silicon Valley unless
you tell them otherwise) and you want to fix it, you need to add a line
similar to set TZ=EST+05EDT
to your
autoexec.bat file (goodness only knows how to fix Bill Gates’ new non-DOS
wonders...), but if you are not in the Eastern Time Zone (eastern United
States), you will need to use the correct time zone offset for your area.
If you are using Windows 95, make sure you have supplied the correct settings
in the Date/Time portion of the Control Panel.
The saga continues. . .
In December of 2000, I had need of this code in a Perl script. All year I
had been “fixing” JavaScript and Perl scripts because neither language was/is
Y2K-compliant and scripts variously reported year 2000 as either “0” or “100.”
Both JavaScript and Perl (and perhaps other computer languages) were written
such that 1 January 1970 is time 0. JavaScript keeps track of times before
then as negative milliseconds from that time. For example, if JavaScript is
given a date of
EarlyDate = new Date(1963,10,22,14,0,0);
,
this is interpreted as
milliseconds from 1-1-1970. Perl’s date functions are more limited than
JavaScript’s, and it totally refuses to deal with negative time values.
Thus, while SomeDate = new Date(-123);
will work in JavaScript,
$SomeDate = time(-123);
does not work
in Perl.
However, JavaScript does not easily deal with dates before the year 1000.
For example,
EarlyDate = new Date(63,10,22,14,0,0);
is interpreted as
milliseconds from 1-1-1970, but that’s not what I wanted. If I go to all the
trouble to “manually” calculate the necessary number of milliseconds, I can
force it to use the correct date.
theMsec = (-1906 * 365.25 * 24 * 3600 * 1000);
returns
theMsec = (-1906 * 365.25 * 24 * 3600 * 1000) + (-25 * 24 * 3600 * 1000);
returns
and finally,
theMsec = (-1906 * 365.25 * 24 * 3600 * 1000) + (-25 * 24 * 3600 * 1000) + (7 * 3600 * 1000);
returns
However, that date was not a Thursday! According to the astronomy book cited above, back in 1582, Pope Gregory decreed that the days 5 through 14 October of that year just did not/do not exist. JavaScript, however, reports the day before 15 October 1582 as being 14 October, not 4 October, and thus, any day-of-week calculations it does before then are ten days off. Also, Pope Gregory adjusted our time calculations such that, since then, years that end in “00” are only leap years if they are divisible by 400. That means that 1600 and 2000 were leap years, but 1700, 1800, and 1900 were not. JavaScript dutifully takes that into account, so as far as it is concerned, 29 February 1500 did not exist. That means that day-of-week calculations for any dates in the 1400s are 11 days off. While I haven’t checked, I would suppose the same is true for 1400, 1300, etc.
So... back to the handy astronomy book, which includes calculations for what astronomers call “Julian dates” in honor of Julius Caesar. Now, the JavaScript code looks like this (isLegal is another function that tests to see if user input is really a valid number):
var today = new Date(); var tzone = today.getTimezoneOffset() / 60; // in min so convert to hours tzhr = tzone; tzone = tzone / 24; // convert to fraction of a day var FractDay = 0; // EpochDate = new Date(89, 11, 31, 00, 00, 00); // equivalent of the book's 0 Jan 90 // is equiv to JD 2447891.5 var Epoch = 2447891.5; function phasecalc() { //button click handler yyy = document.form1.theYear.value; isNameOK = 1; NotASpace = 0; isLegal(yyy, 1); while (isNameOK == 0 || NotASpace == 0 || newNameStr > 9999 || newNameStr < -4713) { testNo = prompt ('Your year number can’t be \"' + newNameStr + '\"! Put a valid year here:', newNameStr); isLegal(testNo, 1); } document.form1.theYear.value = yyy = parseFloat(newNameStr); newNameStr = ""; isLeap = 0; testLeap = yyy % 4; // will be 0 in leap year testCent = yyy % 100; // is it a century year testSkip = yyy % 400; // for 1700, 1800, 1900, don't do leap year, (but yes for 1500, 1600, 2000) if ((yyy <=1582 && testLeap == 0) || (yyy > 1582 && testLeap == 0 && testCent != 0) || (yyy > 1582 && testLeap == 0 && testCent == 0 && testSkip == 0)) { isLeap == 1; } mmm = document.form1.theMnth.value; isNameOK = 1; NotASpace = 0; isLegal(mmm, 1); while (isNameOK == 0 || NotASpace == 0 || newNameStr > 12 || newNameStr < 1) { testNo = prompt ('Your month number can’t be \"' + newNameStr + '\"! Put a valid month here:', newNameStr); isLegal(testNo, 1); } document.form1.theMnth.value = mmm = parseFloat(newNameStr); newNameStr = ""; ddd = document.form1.theDate.value; isNameOK = 1; NotASpace = 0; isLegal(ddd, 1); while (isNameOK == 0 || NotASpace == 0 || newNameStr < 1 || ((mmm == 1 || mmm == 3 || mmm == 5 || mmm == 7 || mmm == 8 || mmm == 10 || mmm == 12) && newNameStr > 31) || ((mmm == 4 || mmm == 6 || mmm == 9 || mmm == 11) && newNameStr > 30) || (mmm == 2 && isLeap == 0 && newNameStr > 28) || (mmm == 2 && isLeap == 1 && newNameStr > 29)) { testNo = prompt ('Your date number can’t be \"' + newNameStr + '\"! Put a valid date here:', newNameStr); isLegal(testNo, 1); } document.form1.theDate.value = ddd = parseFloat(newNameStr); newNameStr = ""; hhh = document.form1.theHour.value; isNameOK = 1; NotASpace = 0; isLegal(hhh, 1); while (isNameOK == 0 || NotASpace == 0 || newNameStr < 0 || newNameStr > 23 || (yyy == -4713 && mmm == 1 && ddd == 1 && hhh < 12)) { testNo = prompt ('Your hour number can’t be \"' + newNameStr + '\"! Put a valid hour here:', newNameStr); isLegal(testNo, 1); } document.form1.theHour.value = hhh = parseFloat(newNameStr); newNameStr = ""; FractDay = hhh / 24; mmn = document.form1.theMins.value; isNameOK = 1; NotASpace = 0; isLegal(mmn, 1); while (isNameOK == 0 || NotASpace == 0 || newNameStr > 59 || newNameStr < 0) { testNo = prompt ('Your minutes number can’t be \"' + newNameStr + '\"! Put a valid minutes here:', newNameStr); isLegal(testNo, 1); } document.form1.theMins.value = mmn = parseFloat(newNameStr); newNameStr = ""; FractDay += mmn / 60 / 24; // this calculates the Julian Date if (mmm < 3) { // if 1 or 2 (this has been changed to 1-base) yyy--; mmm += 12; } if ((yyy >= 1583) || (yyy == 1582 && mmm > 10) || (yyy == 1582 && mmm == 10 && ddd >= 15)) { // if it's after Gregory changed the calendar AtoJD = Math.floor(yyy / 100); BtoJD = 2 - AtoJD + Math.floor(AtoJD / 4); } else { BtoJD = 0; } if (yyy < 0) { CtoJD = Math.ceil((365.25 * yyy) - 0.75); } else { CtoJD = Math.floor(365.25 * yyy); } DtoJD = Math.floor(30.6001 * (mmm + 1)); // gotta use 1 bec mmm is 1-based JD = parseFloat(BtoJD) + parseFloat(CtoJD) + parseFloat(DtoJD) + parseFloat(ddd) + parseFloat(1720994.5); // add on hr & min fract of a day JDnow = JD + FractDay; // because I was also using this for something else, // correct for time zone after convert to JD // if >= 1990, use local time zone, otherwise assume GMT // note, it doesn't matter if it calculates the date correctly if all we want is the timezone // just remember that the time zone correction must first be converted to a fraction of a day if (yyy >= 1990) { JDnow += tzone; } // here is where the previous calculations start // note the new way of calculating D -- the answer is the same D = JDnow - Epoch; // find diff from 31 Dec 1989 var n = D * (360 / 365.242191); //no 46-3 if (n > 0) { n = n - Math.floor(Math.abs(n / 360)) * 360; //no 46-3 } else { n = n + (360 + Math.floor(Math.abs(n / 360)) * 360); //no 46-3 } var Mo = n + 279.403303 - 282.768422; //no 46-4; if(Mo < 0) { Mo = Mo + 360 } //no 46-4 var Ec = 360 * .016713 * Math.sin(Mo * 3.141592654 / 180) / 3.141592654; //no 46-5 var lamda = n + Ec + 279.403303; //no 46-6 if(lamda > 360) { lamda = lamda - 360 } //no 46-6 var l = 13.1763966 * D + 318.351648; //no 65-4 if (l > 0) { l = l - Math.floor(Math.abs(l / 360)) * 360; //no 65-4 } else { l = l + (360 + Math.floor(Math.abs(l / 360)) * 360); //no 65-4 } var Mm = l - .1114041 * D - 36.34041; //no 65-5 if (Mm > 0) { Mm = Mm - Math.floor(Math.abs(Mm / 360)) * 360; //no 65-5 } else { Mm = Mm + (360 + Math.floor(Math.abs(Mm / 360)) * 360); //no 65-5 } var N65 = 318.510107 - .0529539 * D; //no 65-6 if (N65 > 0) { N65 = N65 - Math.floor(Math.abs(N65 / 360)) * 360; //no 65-6 } else { N65 = N65 + (360 + Math.floor(Math.abs(N65 / 360)) * 360); //no 65-6 } var Ev = 1.2739 * Math.sin((2 * (l - lamda) - Mm) * 3.141592654 / 180); //no 65-7 var Ae = .1858 * Math.sin(Mo * 3.141592654 / 180); //no 65-8 var A3 = .37 * Math.sin(Mo * 3.141592654 / 180); //no 65-8 var Mmp = Mm + Ev - Ae - A3; //no 65-9 var Ec = 6.2886 * Math.sin(Mmp * 3.141592654 / 180); //no 65-10 var A4 = .214 * Math.sin((2 * Mmp) * 3.141592654 / 180); //no 65-11 var lp = l + Ev + Ec - Ae + A4; //no 65-12 var V = .6583 * Math.sin((2 * (lp - lamda)) * 3.141592654 / 180); //no 65-13 var lpp = lp + V; //no 65-14 var D67 = lpp - lamda; //no 67-2 Ff = .5 * (1 - Math.cos(D67 * 3.141592654 / 180)); //no 67-3 Xx = (Math.sin(D67 * 3.141592654 / 180)); // I added this to distinguish first from last quarters // figure out what phase the moon is in and what icon to use to go with it if(Ff < .02) { //new document.form1.Phase.src = "../../graphics/steincarter/moon/phase01.gif" document.form1.moonpic.src = "../../graphics/steincarter/moon/moon01.gif" } if((Ff > .45) && (Ff < .55) && (Xx > 0)) { //first document.form1.Phase.src = "../../graphics/steincarter/moon/phase03.gif" document.form1.moonpic.src = "../../graphics/steincarter/moon/moon03.gif" } if((Ff > .45) && (Ff < .55) && (Xx < 0)) { //last document.form1.Phase.src = "../../graphics/steincarter/moon/phase07.gif" document.form1.moonpic.src = "../../graphics/steincarter/moon/moon07.gif" } if(Ff > .98) { //full document.form1.Phase.src = "../../graphics/steincarter/moon/phase05.gif" document.form1.moonpic.src = "../../graphics/steincarter/moon/moon05.gif" } if((Ff > .02) && (Ff < .45) && (Xx > 0)) { //waxing document.form1.Phase.src = "../../graphics/steincarter/moon/phase02.gif" document.form1.moonpic.src = "../../graphics/steincarter/moon/moon02.gif" } if((Ff > .02) && (Ff < .45) && (Xx < 0)) { //waning document.form1.Phase.src = "../../graphics/steincarter/moon/phase08.gif" document.form1.moonpic.src = "../../graphics/steincarter/moon/moon08.gif" } if((Ff > .55) && (Ff < .98) && (Xx > 0)) { //waxing gibbous document.form1.Phase.src = "../../graphics/steincarter/moon/phase04.gif" document.form1.moonpic.src = "../../graphics/steincarter/moon/moon04.gif" } if((Ff > .55) && (Ff < .98) && (Xx < 0)) { //waning gibbous document.form1.Phase.src = "../../graphics/steincarter/moon/phase06.gif" document.form1.moonpic.src = "../../graphics/steincarter/moon/moon06.gif" } } |
Thus, for the date 22 Nov 63 (not 1963) at 00:00 GMT, the Julian date would be
I would ask that if you choose to make use of this code, that you please give credit where credit is due.