<html>
<head>
<title>Lunar Phase Calculator</title>
<link rel="SHORTCUT ICON" HREF="/~srschmitt/favicon.ico">
<link rel="stylesheet" type="text/css" href="standard.css">
<script language=JavaScript SRC=feedback.js></script>

<script language=JavaScript>
<!-- hide

var n0 = parseInt( "0" );
var f0 = parseFloat( "0.0" );
var AG = f0;   // Moon's age
var DI = f0;   // Moon's distance in earth radii
var LA = f0;   // Moon's ecliptic latitude
var LO = f0;   // Moon's ecliptic longitude
var Phase = " ";
var Zodiac = " ";

function initialize()
{
    var d = new Date();

    document.calc.year.value  = d.getFullYear();
    document.calc.month.value = d.getMonth() + 1;
    document.calc.day.value   = d.getDate();
}

function calculate()
{
    var year  = parseInt( document.calc.year.value, 10 );
    var month = parseInt( document.calc.month.value, 10 );
    var day   = parseInt( document.calc.day.value, 10 );

    if( !isdayofmonth( year, month, day ) )
    {
        alert( "Invalid date" );
        return;
    }

    moon_posit( year, month, day );

    document.calc.age.value = round2( AG );
    document.calc.dst.value = round2( DI );
    document.calc.faz.value = Phase;
    document.calc.lat.value = round2( LA );
    document.calc.lon.value = round2( LO );
    document.calc.sgn.value = Zodiac;
}

var n28 = parseInt( "28" );
var n30 = parseInt( "30" );
var n31 = parseInt( "31" );
var dim = new Array( n31, n28, n31, n30, n31, n30, n31, n31, n30, n31, n30, n31 );

function isdayofmonth( y, m, d )
{
    if( m != 2 )
    {
        if( 1 <= d && d <= dim[m-1] )
            return true;
        else
            return false;
    }

    var feb = dim[1];

    if( isleapyear( y ) )
        feb += 1;                                   // is leap year

    if( 1 <= d && d <= feb )
        return true;

    return false;
}

function isleapyear( y )
{
    var x = Math.floor( y - 4*Math.floor( y/4 ) );
    var w = Math.floor( y - 100*Math.floor( y/100 ) );
    var z = Math.floor( y - 400*Math.floor( y/400 ) );

    if( x == 0 )                           // possible leap year
    {
        if( w == 0 && z != 0 )
            return false;                  // not leap year
        else
            return true;                   // is leap year
    }

    return false;
}

function backup( n )
{
    var year = parseInt( document.calc.year.value, 10 );
    var month = parseInt( document.calc.month.value, 10 );
    var day = parseInt( document.calc.day.value, 10 );

    switch( n )
    {
    case 1:
        document.calc.year.value = year - 1;
        calculate();
        break;
    case 2:
        if( month < 2 )
        {
            document.calc.month.value = 12;
            document.calc.year.value = year - 1;
        }
        else
            document.calc.month.value = month - 1;
        calculate();
        break;
    case 3:
        if( day < 2 )
        {
            if( month < 2 )
            {
                document.calc.month.value = 12;
                document.calc.year.value = year - 1;
            }
            else
                document.calc.month.value = month - 1;

            month = parseInt( document.calc.month.value, 10 );
            if( month == 2 && isleapyear( year ) )
                document.calc.day.value = 29;
            else
                document.calc.day.value = dim[month-1];
        }
        else
            document.calc.day.value = day - 1;
        calculate();
        break;
    }
}

function advance( n )
{
    var year = parseInt( document.calc.year.value, 10 );
    var month = parseInt( document.calc.month.value, 10 );
    var day = parseInt( document.calc.day.value, 10 );

    switch( n )
    {
    case 1:
        document.calc.year.value = year + 1;
        calculate();
        break;
    case 2:
        if( month < 12 )
            document.calc.month.value = month + 1;
        else
        {
            document.calc.month.value = 1;
            document.calc.year.value = year + 1;
        }
        calculate();
        break;
    case 3:
        if( isdayofmonth( year, month, day + 1 ) )
            document.calc.day.value = day + 1;
        else
        {
            if( month < 12 )
                document.calc.month.value = month + 1;
            else
            {
                document.calc.month.value = 1;
                document.calc.year.value = year + 1;
            }

            document.calc.day.value = 1;
        }
        calculate();
        break;
    }
}

// compute moon position and phase
function moon_posit( Y, M, D )
{
    var YY = n0;
    var MM = n0;
    var K1 = n0;
    var K2 = n0;
    var K3 = n0;
    var JD = n0;
    var IP = f0;
    var DP = f0;
    var NP = f0;
    var RP = f0;

    // calculate the Julian date at 12h UT
    YY = Y - Math.floor( ( 12 - M ) / 10 );
    MM = M + 9;
    if( MM >= 12 ) MM = MM - 12;

    K1 = Math.floor( 365.25 * ( YY + 4712 ) );
    K2 = Math.floor( 30.6 * MM + 0.5 );
    K3 = Math.floor( Math.floor( ( YY / 100 ) + 49 ) * 0.75 ) - 38;

    JD = K1 + K2 + D + 59;                  // for dates in Julian calendar
    if( JD > 2299160 ) JD = JD - K3;        // for Gregorian calendar

    // calculate moon's age in days
    IP = normalize( ( JD - 2451550.1 ) / 29.530588853 );
    AG = IP*29.53;

    if(      AG <  1.84566 ) Phase = "NEW";
    else if( AG <  5.53699 ) Phase = "Evening crescent";
    else if( AG <  9.22831 ) Phase = "First quarter";
    else if( AG < 12.91963 ) Phase = "Waxing gibbous";
    else if( AG < 16.61096 ) Phase = "FULL";
    else if( AG < 20.30228 ) Phase = "Waning gibbous";
    else if( AG < 23.99361 ) Phase = "Last quarter";
    else if( AG < 27.68493 ) Phase = "Morning crescent";
    else                     Phase = "NEW";

    IP = IP*2*Math.PI;                      // Convert phase to radians

    // calculate moon's distance
    DP = 2*Math.PI*normalize( ( JD - 2451562.2 ) / 27.55454988 );
    DI = 60.4 - 3.3*Math.cos( DP ) - 0.6*Math.cos( 2*IP - DP ) - 0.5*Math.cos( 2*IP );

    // calculate moon's ecliptic latitude
    NP = 2*Math.PI*normalize( ( JD - 2451565.2 ) / 27.212220817 );
    LA = 5.1*Math.sin( NP );

    // calculate moon's ecliptic longitude
    RP = normalize( ( JD - 2451555.8 ) / 27.321582241 );
    LO = 360*RP + 6.3*Math.sin( DP ) + 1.3*Math.sin( 2*IP - DP ) + 0.7*Math.sin( 2*IP );

    if(      LO <  33.18 ) Zodiac = "Pisces";
    else if( LO <  51.16 ) Zodiac = "Aries";
    else if( LO <  93.44 ) Zodiac = "Taurus";
    else if( LO < 119.48 ) Zodiac = "Gemini";
    else if( LO < 135.30 ) Zodiac = "Cancer";
    else if( LO < 173.34 ) Zodiac = "Leo";
    else if( LO < 224.17 ) Zodiac = "Virgo";
    else if( LO < 242.57 ) Zodiac = "Libra";
    else if( LO < 271.26 ) Zodiac = "Scorpio";
    else if( LO < 302.49 ) Zodiac = "Sagittarius";
    else if( LO < 311.72 ) Zodiac = "Capricorn";
    else if( LO < 348.58 ) Zodiac = "Aquarius";
    else                   Zodiac = "Pisces";

    // so longitude is not greater than 360!
    if ( LO > 360 ) LO = LO - 360;
}

// round to 2 decimal places
function round2( x )
{
    return ( Math.round( 100*x )/100.0 );
}

// normalize values to range 0...1
function normalize( v )
{
    v = v - Math.floor( v  );
    if( v < 0 )
        v = v + 1;

    return v;
}

// clear input
function allclear()
{
    document.calc.year.value='0';
    document.calc.month.value='0';
    document.calc.day.value='0';
}
// unhide -->
</script>
</head>
<body bgcolor="white" text="black" onLoad=initialize()>

<!--[TOP]-->
<center>
<!-- google -->

<script type="text/javascript"><!--
google_ad_client = "pub-8195248024094868";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- google -->
</center>
<!--[END]-->

<hr>
|<a HREF="index.html"> home </a>
|<A href="scriptindex.html"> contents </A>

|<a HREF="#top" onClick=feedback()> send comment </a>
|<a HREF="#top" onClick=send_to()> send link </a>
|<a HREF="#top" onClick=bookmark()> add bookmark </a>|
<hr>

<h2>Lunar Phase Calculator</h2>
<h4>by Stephen R. Schmitt</h4>

<form name="calc">
<table>
<tr>
<td><input type="button" VALUE="<<" onClick="backup( 1 )">
<td align=right>year
<td><input type="text" value="0" NAME="year"  size="5" maxlength="30">
<td><input type="button" VALUE=">>" onClick="advance( 1 )">
<tr>
<td><input type="button" VALUE="<<" onClick="backup( 2 )">
<td align=right>month
<td><input type="text" value="0" NAME="month" size="5" maxlength="30">
<td><input type="button" VALUE=">>" onClick="advance( 2 )">
<tr>
<td><input type="button" VALUE="<<" onClick="backup( 3 )">
<td align=right>day
<td><input type="text" value="0" NAME="day"   size="5" maxlength="30">

<td><input type="button" VALUE=">>" onClick="advance( 3 )">
</table>

<p><input type="button" VALUE="calculate" onClick="calculate()">

<table>
<tr>
<td align=right>Moon's age from new :
<td><input type="text"  value="0" NAME="age" size="5" maxlength="30">
<td> days
<td align=right>Moon is :
<td><input type="text"  value="0" NAME="faz" size="20" maxlength="30">
<tr>
<td align=right>Distance :
<td><input type="text"  value="0" NAME="dst" size="5" maxlength="30">
<td> Earth radii

<tr>
<td align=right>Ecliptic latitude :
<td><input type="text"  value="0" NAME="lat" size="5" maxlength="30">
<td> degrees
<tr>
<td align=right>Ecliptic longitude :
<td><input type="text"  value="0" NAME="lon" size="5" maxlength="30">
<td> degrees
<td align=right>Moon is in :
<td><input type="text"  value="0" NAME="sgn" size="20" maxlength="30">
</table>
<p><input type="button" VALUE="clear" onClick="allclear()">
</form>
<hr>
<a name=contents>

<p><b>Contents</b></p>
<ol>
<li><a href="#about">About</a>
<li><a href="#source">Source code</a>
<li><a href="#discussion">Discussion</a>
</ol>
<hr>
<a name=about>
<p>
<b>About</b></p>
<p>
This JavaScript program calculates the phase and position of the moon for a given date. It was adapted from a BASIC program from the <i>Astronomical Computing</i> column of <a href="http://skyandtelescope.com/">Sky & Telescope</a>, April 1994.

<p>
The calculator will initialize itself, if possible, to your computer's day, month, and year. The day, month, and year can be changed using the buttons on the calculator. To advance press one of the [<b> &gt;&gt; </b>] keys; to backup, press one of the [<b> &lt;&lt; </b>] keys.
<p>
<a href="#contents">Contents</a>
<hr>
<a name=source>
<p>
<b>Source Code</b></p>
<p>

The Java Script source code for this program can be viewed by using the View|Source command of your web browser.
<p>
You may use or modify this source code in any way you find useful, provided that you agree that the author has no warranty, obligations or liability.  You must determine the suitablility of this source code for your use.
<p>
<a href="#contents">Contents</a>
<hr>
<a name=discussion>
<p>
<b>Discussion</b></p>
<p>
This program helps anyone who needs to know the Moon's phase (age), distance, and position along the ecliptic on any date within several thousand years in the past or future.
<p>
The ecliptic longitude is measured from the vernal equinox along the ecliptic in the direction of the sun's apparent motion through the stars. The moon's ecliptic longitude is calculated as well as the corresponding zodiac constellation. The ecliptic latitude is positive if north of the ecliptic and negative if south. The age of the moon in days as well as its visual phase are given.
<p>
<a href="#contents">Contents</a>

<hr>

<!--[BOTTOM]-->
<center>
<!-- google -->
<script type="text/javascript"><!--
google_ad_client = "pub-8195248024094868";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_channel ="";
//--></script>
<script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- google -->
</center>
<!--[END]-->
<p align=center><a href="http://www.abcd-classics.com">AbCd Classics - free on-line books</a>
<hr>
Copyright &copy; 2004, Stephen R. Schmitt

</body>
</html>
