Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // SunriseSunset Class (2011-05-01)
- // Implementation of http://williams.best.vwh.net/sunrise_sunset_algorithm.htm
- //
- // Copyright (c) 2011, Preston Hunt <me@prestonhunt.com>
- // All rights reserved.
- //
- // (BSD License)
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions
- // are met:
- //
- // Redistributions of source code must retain the above copyright
- // notice, this list of conditions and the following disclaimer.
- // Redistributions in binary form must reproduce the above copyright
- // notice, this list of conditions and the following disclaimer in the
- // documentation and/or other materials provided with the
- // distribution.
- //
- // The name of Preston Hunt may not be used to endorse or promote
- // products derived from this software without specific prior written
- // permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- // COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- // OF THE POSSIBILITY OF SUCH DAMAGE.
- //
- // Provides sunrise and sunset times for specified date and position.
- // All dates are UTC. Year is 4-digit. Month is 1-12. Day is 1-31.
- // Longitude is positive for east, negative for west. Latitude is
- // positive for north, negative for south.
- //
- // Sample usage:
- // var tokyo = new SunriseSunset( 2011, 1, 19, 35+40/60, 139+45/60);
- // tokyo.sunriseUtcHours() --> 21.8199 = 21:49 GMT
- // tokyo.sunsetUtcHours() --> 7.9070 = 07:54 GMT
- // tokyo.sunriseLocalHours(9) --> 6.8199 = 06:49 at GMT+9
- // tokyo.sunsunsetLocalHours(9) --> 16.9070 = 16:54 at GMT+9
- // tokyo.isDaylight(1.5) --> true
- //
- // var losangeles = new SunriseSunset( 2011, 1, 19, 34.05, -118.233333333 );
- // etc.
- var SunriseSunset = function( utcFullYear, utcMonth, utcDay, latitude, longitude ) {
- this.zenith = 90 + 50/60; // offical = 90 degrees 50'
- // civil = 96 degrees
- // nautical = 102 degrees
- // astronomical = 108 degrees
- this.utcFullYear = utcFullYear;
- this.utcMonth = utcMonth;
- this.utcDay = utcDay;
- this.latitude = latitude;
- this.longitude = longitude;
- this.rising = true; // set to true for sunrise, false for sunset
- this.lngHour = this.longitude / 15;
- };
- SunriseSunset.prototype = {
- sin: function( deg ) { return Math.sin( deg * Math.PI / 180 ); },
- cos: function( deg ) { return Math.cos( deg * Math.PI / 180 ); },
- tan: function( deg ) { return Math.tan( deg * Math.PI / 180 ); },
- asin: function( x ) { return (180/Math.PI) * Math.asin(x); },
- acos: function( x ) { return (180/Math.PI) * Math.acos(x); },
- atan: function( x ) { return (180/Math.PI) * Math.atan(x); },
- getDOY: function() {
- var month = this.utcMonth,
- year = this.utcFullYear,
- day = this.utcDay;
- var N1 = Math.floor( 275 * month / 9 );
- var N2 = Math.floor( (month + 9) / 12 );
- var N3 = (1 + Math.floor((year - 4 * Math.floor(year / 4 ) + 2) / 3));
- var N = N1 - (N2 * N3) + day - 30;
- return N;
- },
- approximateTime: function() {
- var doy = this.getDOY();
- if ( this.rising ) {
- return doy + ((6 - this.lngHour) / 24);
- } else {
- return doy + ((18 - this.lngHour) / 24);
- }
- },
- meanAnomaly: function() {
- var t = this.approximateTime();
- return (0.9856 * t) - 3.289;
- },
- trueLongitude: function() {
- var M = this.meanAnomaly();
- var L = M + (1.916 * this.sin(M)) + (0.020 * this.sin(2 * M)) + 282.634;
- return L % 360;
- },
- rightAscension: function() {
- var L = this.trueLongitude();
- var RA = this.atan(0.91764 * this.tan(L));
- RA %= 360;
- var Lquadrant = (Math.floor( L/90)) * 90;
- var RAquadrant = (Math.floor(RA/90)) * 90;
- RA = RA + (Lquadrant - RAquadrant);
- RA /= 15;
- return RA;
- },
- sinDec: function() {
- var L = this.trueLongitude(),
- sinDec = 0.39782 * this.sin(L);
- return sinDec;
- },
- cosDec: function() {
- return this.cos(this.asin(this.sinDec()));
- },
- localMeanTime: function() {
- var cosH = (this.cos(this.zenith) - (this.sinDec() * this.sin(this.latitude)))
- / (this.cosDec() * this.cos(this.latitude));
- if (cosH > 1) {
- return "the sun never rises on this location (on the specified date)";
- } else if (cosH < -1) {
- return "the sun never sets on this location (on the specified date)";
- } else {
- var H = this.rising ? 360 - this.acos(cosH) : this.acos(cosH);
- H /= 15;
- var RA = this.rightAscension();
- var t = this.approximateTime();
- var T = H + RA - (0.06571 * t) - 6.622;
- return T;
- }
- },
- hoursRange: function( h ) {
- return (h+24) % 24;
- },
- UTCTime: function() {
- var T = this.localMeanTime();
- var UT = T - this.lngHour;
- return this.hoursRange( UT );
- //if ( UT < 0 ) UT += 24;
- //return UT % 24;
- },
- sunriseUtcHours: function() {
- this.rising = true;
- return this.UTCTime();
- },
- sunsetUtcHours: function() {
- this.rising = false;
- return this.UTCTime();
- },
- sunriseLocalHours: function(gmt) {
- return this.hoursRange( gmt + this.sunriseUtcHours() );
- },
- sunsetLocalHours: function(gmt) {
- return this.hoursRange( gmt + this.sunsetUtcHours() );
- },
- isDaylight: function( utcCurrentHours ) {
- var sunriseHours = this.sunriseUtcHours(),
- sunsetHours = this.sunsetUtcHours();
- if ( sunsetHours < sunriseHours ) {
- // Either the sunrise or sunset time is for tomorrow
- if ( utcCurrentHours > sunriseHours ) {
- return true;
- } else if ( utcCurrentHours < sunsetHours ) {
- return true;
- } else {
- return false;
- }
- }
- if ( utcCurrentHours >= sunriseHours ) {
- return utcCurrentHours < sunsetHours;
- }
- return false;
- }
- };
- function SunriseSunsetTest() {
- var testcases = {
- 'Los Angeles': {
- 'lat': 34.05, 'lon': -118.23333333,
- 'tests': [
- { 'year': 2011, 'month': 1, 'day': 22, 'utcHours': 19.6666666, 'isDaylight': true }
- ]
- },
- 'Berlin': {
- 'lat': 52.5, 'lon': 13.366666667,
- 'tests': [
- { 'year': 2011, 'month': 1, 'day': 25, 'utcHours': 1.25, 'isDaylight': false },
- { 'year': 2011, 'month': 2, 'day': 22, 'utcHours': 2.5, 'isDaylight': false }
- ]
- },
- 'Tokyo': {
- 'lat': 35+40/60, 'lon': 139+45/60,
- 'tests': [
- { 'year': 2011, 'month': 1, 'day': 23, 'utcHours': 1.5, 'isDaylight': true },
- { 'year': 2011, 'month': 1, 'day': 23, 'utcHours': 22.5, 'isDaylight': true }
- ]
- },
- 'Seoul': {
- 'lat': 37.55, 'lon': 126.966666667,
- 'tests': [
- { 'year': 2011, 'month': 4, 'day': 10, 'utcHours': 15+30/60, 'isDaylight': false }
- ]
- },
- 'New Delhi': {
- 'lat': 35+40/60, 'lon': 139+45/60,
- 'tests': [
- ]
- },
- 'Sydney': {
- 'lat': -(33+55/60), 'lon': 151+17/60,
- 'tests': [
- { 'year': 2011, 'month': 5, 'day': 1, 'utcHours': 17+53/60, 'isDaylight': false }
- ]
- },
- 'Santiago': {
- 'lat': -(33+26/60), 'lon': -(70+40/60),
- 'tests': [
- { 'year': 2011, 'month': 5, 'day': 1, 'utcHours': 17+54/60, 'isDaylight': true }
- ]
- }
- };
- var tests_run = 0;
- var tests_failed = 0;
- for ( var city_name in testcases ) {
- var city = testcases[ city_name ];
- for ( var i=0; i<city.tests.length; i++ ) {
- var t = city.tests[i];
- var ss = new SunriseSunset( t.year, t.month, t.day, city.lat, city.lon );
- var expected = t.isDaylight;
- var result = ss.isDaylight( t.utcHours );
- var passed = result === expected;
- tests_run++;
- if ( ! passed ) tests_failed++;
- /*jsl:ignore*/
- print( city_name, t.year, t.month, t.day, t.utcHours, "passed:", passed );
- if ( ! passed ) {
- print( "sunriseUtcHours=" + ss.sunriseUtcHours() +
- ", sunsetUtcHours=" + ss.sunsetUtcHours() );
- }
- /*jsl:end*/
- }
- }
- /*jsl:ignore*/
- print( "tests: " + tests_run, "failed: " + tests_failed );
- /*jsl:end*/
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement