presto8

Untitled

Jul 31st, 2011
2,458
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //   SunriseSunset Class (2013-04-21)
  2. //
  3. // OVERVIEW
  4. //
  5. //   Implementation of http://williams.best.vwh.net/sunrise_sunset_algorithm.htm
  6. //
  7. // LICENSE
  8. //
  9. //   Copyright 2011-2013 Preston Hunt <me@prestonhunt.com>
  10. //
  11. //   Licensed under the Apache License, Version 2.0 (the "License");
  12. //   you may not use this file except in compliance with the License.
  13. //   You may obtain a copy of the License at
  14. //
  15. //       http://www.apache.org/licenses/LICENSE-2.0
  16. //
  17. //   Unless required by applicable law or agreed to in writing, software
  18. //   distributed under the License is distributed on an "AS IS" BASIS,
  19. //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  20. //   See the License for the specific language governing permissions and
  21. //   limitations under the License.
  22. //
  23. // DESCRIPTION
  24. //
  25. //   Provides sunrise and sunset times for specified date and position.
  26. //   All dates are UTC.  Year is 4-digit.  Month is 1-12.  Day is 1-31.
  27. //   Longitude is positive for east, negative for west. Latitude is
  28. //   positive for north, negative for south.
  29. //
  30. // SAMPLE USAGE
  31. //
  32. //   var tokyo = new SunriseSunset( 2011, 1, 19, 35+40/60, 139+45/60);
  33. //   tokyo.sunriseUtcHours()      --> 21.8199 = 21:49 GMT
  34. //   tokyo.sunsetUtcHours()       --> 7.9070  = 07:54 GMT
  35. //   tokyo.sunriseLocalHours(9)   --> 6.8199  = 06:49 at GMT+9
  36. //   tokyo.sunsetLocalHours(9)    --> 16.9070 = 16:54 at GMT+9
  37. //   tokyo.isDaylight(1.5)        --> true
  38. //
  39. //   var losangeles = new SunriseSunset( 2011, 1, 19, 34.05, -118.233333333 );
  40. //   etc.
  41.  
  42. var SunriseSunset = function( utcFullYear, utcMonth, utcDay, latitude, longitude ) {
  43.     this.zenith = 90 + 50/60; //   offical      = 90 degrees 50'
  44.                               //   civil        = 96 degrees
  45.                               //   nautical     = 102 degrees
  46.                               //   astronomical = 108 degrees
  47.  
  48.     this.utcFullYear = utcFullYear;
  49.     this.utcMonth = utcMonth;
  50.     this.utcDay = utcDay;
  51.     this.latitude = latitude;
  52.     this.longitude = longitude;
  53.  
  54.     this.rising = true; // set to true for sunrise, false for sunset
  55.     this.lngHour = this.longitude / 15;
  56. };
  57.  
  58. SunriseSunset.prototype = {
  59.     sin: function( deg ) { return Math.sin( deg * Math.PI / 180 ); },
  60.     cos: function( deg ) { return Math.cos( deg * Math.PI / 180 ); },
  61.     tan: function( deg ) { return Math.tan( deg * Math.PI / 180 ); },
  62.     asin: function( x ) { return (180/Math.PI) * Math.asin(x); },
  63.     acos: function( x ) { return (180/Math.PI) * Math.acos(x); },
  64.     atan: function( x ) { return (180/Math.PI) * Math.atan(x); },
  65.  
  66.     getDOY: function() {
  67.         var month = this.utcMonth,
  68.             year = this.utcFullYear,
  69.             day = this.utcDay;
  70.  
  71.         var N1 = Math.floor( 275 * month / 9 );
  72.         var N2 = Math.floor( (month + 9) / 12 );
  73.         var N3 = (1 + Math.floor((year - 4 * Math.floor(year / 4 ) + 2) / 3));
  74.         var N = N1 - (N2 * N3) + day - 30;
  75.         return N;
  76.     },
  77.  
  78.     approximateTime: function() {
  79.         var doy = this.getDOY();
  80.         if ( this.rising ) {
  81.             return doy + ((6 - this.lngHour) / 24);
  82.         } else {
  83.             return doy + ((18 - this.lngHour) / 24);
  84.         }
  85.     },
  86.  
  87.     meanAnomaly: function() {
  88.         var t = this.approximateTime();
  89.         return (0.9856 * t) - 3.289;
  90.     },
  91.  
  92.     trueLongitude: function() {
  93.         var M = this.meanAnomaly();
  94.         var L = M + (1.916 * this.sin(M)) + (0.020 * this.sin(2 * M)) + 282.634;
  95.         return L % 360;
  96.     },
  97.  
  98.     rightAscension: function() {
  99.         var L = this.trueLongitude();
  100.         var RA = this.atan(0.91764 * this.tan(L));
  101.         RA %= 360;
  102.  
  103.         var Lquadrant  = (Math.floor( L/90)) * 90;
  104.         var RAquadrant = (Math.floor(RA/90)) * 90;
  105.         RA = RA + (Lquadrant - RAquadrant);
  106.         RA /= 15;
  107.  
  108.         return RA;
  109.     },
  110.  
  111.     sinDec: function() {
  112.         var L = this.trueLongitude(),
  113.             sinDec = 0.39782 * this.sin(L);
  114.  
  115.         return sinDec;
  116.     },
  117.  
  118.     cosDec: function() {
  119.         return this.cos(this.asin(this.sinDec()));
  120.     },
  121.  
  122.     localMeanTime: function() {
  123.         var cosH = (this.cos(this.zenith) - (this.sinDec() * this.sin(this.latitude)))
  124.             / (this.cosDec() * this.cos(this.latitude));
  125.  
  126.         if (cosH >  1) {
  127.             return "the sun never rises on this location (on the specified date)";
  128.         } else if (cosH < -1) {
  129.             return "the sun never sets on this location (on the specified date)";
  130.         } else {
  131.             var H = this.rising ? 360 - this.acos(cosH) : this.acos(cosH);
  132.             H /= 15;
  133.             var RA = this.rightAscension();
  134.             var t = this.approximateTime();
  135.             var T = H + RA - (0.06571 * t) - 6.622;
  136.             return T;
  137.         }
  138.     },
  139.  
  140.     hoursRange: function( h ) {
  141.         return (h+24) % 24;
  142.     },
  143.  
  144.     UTCTime: function() {
  145.         var T = this.localMeanTime();
  146.         var UT = T - this.lngHour;
  147.         return this.hoursRange( UT );
  148.         //if ( UT < 0 ) UT += 24;
  149.         //return UT % 24;
  150.     },
  151.  
  152.     sunriseUtcHours: function() {
  153.         this.rising = true;
  154.         return this.UTCTime();
  155.     },
  156.  
  157.     sunsetUtcHours: function() {
  158.         this.rising = false;
  159.         return this.UTCTime();
  160.     },
  161.  
  162.     sunriseLocalHours: function(gmt) {
  163.         return this.hoursRange( gmt + this.sunriseUtcHours() );
  164.     },
  165.  
  166.     sunsetLocalHours: function(gmt) {
  167.         return this.hoursRange( gmt + this.sunsetUtcHours() );
  168.     },
  169.  
  170.     // utcCurrentHours is the time that you would like to test for daylight, in hours, at UTC
  171.     // For example, to test if it's daylight in Tokyo (GMT+9) at 10:30am, pass in
  172.     // utcCurrentHours=1.5, which corresponds to 1:30am UTC.
  173.     isDaylight: function( utcCurrentHours ) {
  174.         var sunriseHours = this.sunriseUtcHours(),
  175.             sunsetHours = this.sunsetUtcHours();
  176.  
  177.         if ( sunsetHours < sunriseHours ) {
  178.             // Either the sunrise or sunset time is for tomorrow
  179.             if ( utcCurrentHours > sunriseHours ) {
  180.                 return true;
  181.             } else if ( utcCurrentHours < sunsetHours ) {
  182.                 return true;
  183.             } else {
  184.                 return false;
  185.             }
  186.         }
  187.  
  188.         if ( utcCurrentHours >= sunriseHours ) {
  189.             return utcCurrentHours < sunsetHours;
  190.         }
  191.  
  192.         return false;
  193.     }
  194. };
  195.  
  196. function SunriseSunsetTest() {
  197.     var testcases = {
  198.         'Los Angeles': {
  199.             'lat': 34.05, 'lon': -118.23333333,
  200.             'tests': [
  201.                 { 'year': 2011, 'month': 1, 'day': 22, 'utcHours': 19.6666666, 'isDaylight': true }
  202.             ]
  203.         },
  204.         'Berlin': {
  205.             'lat': 52.5, 'lon': 13.366666667,
  206.             'tests': [
  207.                 { 'year': 2011, 'month': 1, 'day': 25, 'utcHours': 1.25, 'isDaylight': false },
  208.                 { 'year': 2011, 'month': 2, 'day': 22, 'utcHours': 2.5, 'isDaylight': false }
  209.             ]
  210.         },
  211.         'Tokyo': {
  212.             'lat': 35+40/60, 'lon': 139+45/60,
  213.             'tests': [
  214.                 { 'year': 2011, 'month': 1, 'day': 23, 'utcHours': 1.5, 'isDaylight': true },
  215.                 { 'year': 2011, 'month': 1, 'day': 23, 'utcHours': 22.5, 'isDaylight': true }
  216.             ]
  217.         },
  218.         'Seoul': {
  219.             'lat': 37.55, 'lon': 126.966666667,
  220.             'tests': [
  221.                 { 'year': 2011, 'month': 4, 'day': 10, 'utcHours': 15+30/60, 'isDaylight': false }
  222.             ]
  223.         },
  224.         'New Delhi': {
  225.             'lat': 35+40/60, 'lon': 139+45/60,
  226.             'tests': [
  227.             ]
  228.         },
  229.         'Sydney': {
  230.             'lat': -(33+55/60), 'lon': 151+17/60,
  231.             'tests': [
  232.                 { 'year': 2011, 'month': 5, 'day': 1, 'utcHours': 17+53/60, 'isDaylight': false }
  233.             ]
  234.         },
  235.         'Santiago': {
  236.             'lat': -(33+26/60), 'lon': -(70+40/60),
  237.             'tests': [
  238.                 { 'year': 2011, 'month': 5, 'day': 1, 'utcHours': 17+54/60, 'isDaylight': true }
  239.             ]
  240.         }
  241.     };
  242.  
  243.     var tests_run = 0;
  244.     var tests_failed = 0;
  245.  
  246.     for ( var city_name in testcases ) {
  247.         var city = testcases[ city_name ];
  248.         for ( var i=0; i<city.tests.length; i++ ) {
  249.             var t = city.tests[i];
  250.             var ss = new SunriseSunset( t.year, t.month, t.day, city.lat, city.lon );
  251.             var expected = t.isDaylight;
  252.             var result = ss.isDaylight( t.utcHours );
  253.             var passed = result === expected;
  254.  
  255.             tests_run++;
  256.             if ( ! passed ) tests_failed++;
  257.            
  258.             /*jsl:ignore*/
  259.             print( city_name, t.year, t.month, t.day, t.utcHours, "passed:", passed );
  260.             if ( ! passed ) {
  261.                 print( "sunriseUtcHours=" + ss.sunriseUtcHours() +
  262.                         ", sunsetUtcHours=" + ss.sunsetUtcHours() );
  263.             }
  264.  
  265.             /*jsl:end*/
  266.         }
  267.     }
  268.  
  269.     /*jsl:ignore*/
  270.     print( "tests: " + tests_run, "failed: " + tests_failed );
  271.     /*jsl:end*/
  272. }
RAW Paste Data