
/**

*

* Calculates sunrise and sunset times. Based on

* NOAA's algorithm.

*

* The calculations in the NOAA Sunrise/Sunset and Solar Position Calculators

* are based on equations from Astronomical Algorithms, by Jean Meeus. The

* sunrise and sunset results have been verified to be accurate to within a

* minute for locations between +/- 72° latitude, and within 10 minutes outside

* of those latitudes.

*

* This is an implementation of NOAA's low accuracy calculations

*

* Tested against http://www.srrb.noaa.gov/highlights/sunrise/sunrise.html

* Results within 2-3 minutes for places in UK, US and Australia

*

* This javascript port by Bill Chadwick, November 2008 - free for any use.

*

*/



function SunRiseSunSet() {



    /** Converts day of year to fractional year in radians.

    * @return fractional year (radians)

    */

    this.gamma = function(dayOfYear) {



        return ((2 * Math.PI) / 365.0) * (dayOfYear - 1);

    }



    // equation of time - minutes

    this.eqtimeMins = function (dayOfYear) {



        var g = this.gamma(dayOfYear);

        return 229.18 * (0.000075

        + (0.001868 * Math.cos(g))

        - (0.032077 * Math.sin(g))

        - (0.014615 * Math.cos(g * 2.0))

        - (0.040849 * Math.sin(g * 2.0))

        );

    }



    /** Calculates solar declination angle in radians.

    * @return solar declination angle (radians)

    */

    this.declRads = function (dayOfYear) {



        var g = this.gamma(dayOfYear);

        return 0.006918

        - 0.399912 * Math.cos(g)

        + 0.070257 * Math.sin(g)

        - 0.006758 * Math.cos(g * 2.0)

        + 0.000907 * Math.sin(g * 2.0)

        - 0.002697 * Math.cos(g * 3.0)

        + 0.00148 * Math.sin(g * 3.0);

    }



    // sunrise/sunset hour angle, +ha = sunrise, -ha = sunset



    this.haDegrees = function (latitudeDegrees, dayOfYear) {



        var la = latitudeDegrees * (Math.PI / 180.0);

        var decl = this.declRads(dayOfYear);

        return Math.acos(

        (Math.cos(90.833 * (Math.PI / 180.0)) / (Math.cos(la) * Math.cos(decl)))

        - (Math.tan(la) * Math.tan(decl))

        ) * (180.0 / Math.PI);

    }



    //Java Script date to day of year

    this.dayOfYear = function(d){

        var onejan = new Date(d.getUTCFullYear(),0,1);

        return Math.ceil((d - onejan) / 86400000);

    }



    //Java script adjust date from decimal UTC hours

    this.dateFromHours = function(hrs, d){

        var r = new Date(d.getUTCFullYear(),d.getUTCMonth(),d.getUTCDate());

        var mins = (hrs-Math.floor(hrs)) * 60.0;

        hrs = Math.floor(hrs);

        if (hrs >= 24){

            r = new Date(r.getTime() + (24 * 60 * 60 * 1000));

            hrs -= 24;

            }

        else if (hrs < 0){

            hrs += 24;

            r = new Date(r.getTime() - (24 * 60 * 60 * 1000));

        }

        r.setUTCHours(hrs);

        r.setUTCMinutes(Math.round(mins));

        return r;

    }



// Public methods use - for West and South



    this.sunRise = function(latitudeDegrees, longitudeDegrees, jsDate) {



        var doy = this.dayOfYear(jsDate);

        var hrs = (720.0

        + (4 * (-longitudeDegrees - this.haDegrees(latitudeDegrees, doy)))

        - this.eqtimeMins(doy)

        ) / 60.0;

        // -ve hours means the previous day, > 24 hrs means the next day

        return this.dateFromHours(hrs,jsDate);

    }



    this.sunSet = function(latitudeDegrees, longitudeDegrees, jsDate) {



        var doy = this.dayOfYear(jsDate);

        var hrs = (720.0

        + (4 * (-longitudeDegrees + this.haDegrees(latitudeDegrees, doy)))

        - this.eqtimeMins(doy)

        ) / 60.0;

        // -ve hours means the previous day, > 24 hrs means the next day

        return this.dateFromHours(hrs,jsDate);

    }



    this.sunNoon = function(latitudeDegrees, longitudeDegrees, jsDate) {



        var hrs = (720.0

        + (4 * (-longitudeDegrees))

        - this.eqtimeMins(this.dayOfYear(jsDate))

        ) / 60.0;

        // -ve hours means the previous day, > 24 hrs means the next day

        return this.dateFromHours(hrs,jsDate);

    }



}







 
