Guest User

Sunrise/Sunset JavaScript

a guest
Jan 30th, 2011
534
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // SunriseSunset Class (2011-01-30)
  2. //   Implementation of http://williams.best.vwh.net/sunrise_sunset_algorithm.htm
  3. //
  4. //   Copyright (c) 2011, Preston Hunt <[email protected]>
  5. //   All rights reserved.
  6. //
  7. //   Redistribution and use in source and binary forms, with or without
  8. //   modification, are permitted provided that the following conditions
  9. //   are met:
  10. //
  11. //   Redistributions of source code must retain the above copyright
  12. //   notice, this list of conditions and the following disclaimer.
  13. //   Redistributions in binary form must reproduce the above copyright
  14. //   notice, this list of conditions and the following disclaimer in the
  15. //   documentation and/or other materials provided with the
  16. //   distribution.
  17. //
  18. //   The name of Preston Hunt may be used to endorse or promote products
  19. //   derived from this software without specific prior written
  20. //   permission.
  21. //
  22. //   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  23. //   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  24. //   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  25. //   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  26. //   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  27. //   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  28. //   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  29. //   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  30. //   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  31. //   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  32. //   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  33. //   OF THE POSSIBILITY OF SUCH DAMAGE.
  34. //
  35. //   Provides sunrise and sunset times for specified date and position.
  36. //   All dates are UTC.  Year is 4-digit.  Month is 1-12.  Day is 1-31.
  37. //   Longitude is positive for east, negative for west.
  38. //
  39. //   Sample usage:
  40. //   var tokyo = new SunriseSunset( 2011, 1, 19, 35+40/60, 139+45/60);
  41. //   tokyo.sunriseUtcHours()      --> 21.8199 = 21:49 GMT
  42. //   tokyo.sunsetUtcHours()       --> 7.9070  = 07:54 GMT
  43. //   tokyo.sunriseLocalHours(9)   --> 6.8199  = 06:49 at GMT+9
  44. //   tokyo.sunsunsetLocalHours(9) --> 16.9070 = 16:54 at GMT+9
  45. //   tokyo.isDaylight(1.5)        --> true
  46. //
  47. //   var losangeles = new SunriseSunset( 2011, 1, 19, 34.05, -118.233333333 );
  48. //   etc.
  49.  
  50. var SunriseSunset = function( utcFullYear, utcMonth, utcDay, latitude, longitude ) {
  51.     this.zenith = 90 + 50/60; //   offical      = 90 degrees 50'
  52.                               //   civil        = 96 degrees
  53.                               //   nautical     = 102 degrees
  54.                               //   astronomical = 108 degrees
  55.  
  56.     this.utcFullYear = utcFullYear;
  57.     this.utcMonth = utcMonth;
  58.     this.utcDay = utcDay;
  59.     this.latitude = latitude;
  60.     this.longitude = longitude;
  61.  
  62.     this.rising = true; // set to true for sunrise, false for sunset
  63.     this.lngHour = this.longitude / 15;
  64. };
  65.  
  66. SunriseSunset.prototype = {
  67.     sin: function( deg ) { return Math.sin( deg * Math.PI / 180 ); },
  68.     cos: function( deg ) { return Math.cos( deg * Math.PI / 180 ); },
  69.     tan: function( deg ) { return Math.tan( deg * Math.PI / 180 ); },
  70.     asin: function( x ) { return (180/Math.PI) * Math.asin(x); },
  71.     acos: function( x ) { return (180/Math.PI) * Math.acos(x); },
  72.     atan: function( x ) { return (180/Math.PI) * Math.atan(x); },
  73.  
  74.     getDOY: function() {
  75.         var month = this.utcMonth;
  76.         var year = this.utcFullYear;
  77.         var day = this.utcDay;
  78.  
  79.         var N1 = Math.floor( 275 * month / 9 );
  80.         var N2 = Math.floor( (month + 9) / 12 );
  81.         var N3 = (1 + Math.floor((year - 4 * Math.floor(year / 4 ) + 2) / 3));
  82.         var N = N1 - (N2 * N3) + day - 30;
  83.         return N;
  84.     },
  85.  
  86.     approximateTime: function() {
  87.         var doy = this.getDOY();
  88.         if ( this.rising ) {
  89.             return doy + ((6 - this.lngHour) / 24);
  90.         } else {
  91.             return doy + ((18 - this.lngHour) / 24);
  92.         }
  93.     },
  94.  
  95.     meanAnomaly: function() {
  96.         var t = this.approximateTime();
  97.         return (0.9856 * t) - 3.289;
  98.     },
  99.  
  100.     trueLongitude: function() {
  101.         var M = this.meanAnomaly();
  102.         var L = M + (1.916 * this.sin(M)) + (0.020 * this.sin(2 * M)) + 282.634;
  103.         return L % 360;
  104.     },
  105.  
  106.     rightAscension: function() {
  107.         var L = this.trueLongitude();
  108.         var RA = this.atan(0.91764 * this.tan(L));
  109.         RA %= 360;
  110.  
  111.         var Lquadrant  = (Math.floor( L/90)) * 90;
  112.         var RAquadrant = (Math.floor(RA/90)) * 90;
  113.         RA = RA + (Lquadrant - RAquadrant);
  114.         RA /= 15;
  115.  
  116.         return RA;
  117.     },
  118.  
  119.     sinDec: function() {
  120.         var L = this.trueLongitude();
  121.         var sinDec = 0.39782 * this.sin(L);
  122.         return sinDec;
  123.     },
  124.  
  125.     cosDec: function() {
  126.         return this.cos(this.asin(this.sinDec()));
  127.     },
  128.  
  129.     localMeanTime: function() {
  130.         var cosH = (this.cos(this.zenith) - (this.sinDec() * this.sin(this.latitude)))
  131.             / (this.cosDec() * this.cos(this.latitude));
  132.  
  133.         if (cosH >  1) {
  134.             return "the sun never rises on this location (on the specified date)";
  135.         } else if (cosH < -1) {
  136.             return "the sun never sets on this location (on the specified date)";
  137.         } else {
  138.             var H = this.rising ? 360 - this.acos(cosH) : this.acos(cosH);
  139.             H /= 15;
  140.             var RA = this.rightAscension();
  141.             var t = this.approximateTime();
  142.             var T = H + RA - (0.06571 * t) - 6.622;
  143.             return T;
  144.         }
  145.     },
  146.  
  147.     UTCTime: function() {
  148.         var T = this.localMeanTime();
  149.         var UT = T - this.lngHour;
  150.         return UT % 24;
  151.     },
  152.  
  153.     sunriseUtcHours: function() {
  154.         this.rising = true;
  155.         return this.UTCTime();
  156.     },
  157.  
  158.     sunsetUtcHours: function() {
  159.         this.rising = false;
  160.         return this.UTCTime();
  161.     },
  162.  
  163.     hoursRange: function( h ) {
  164.         if ( h >= 24 ) {
  165.             return h - 24;
  166.         } else if ( h < 0 ) {
  167.             return h + 24;
  168.         } else {
  169.             return h;
  170.         }
  171.     },
  172.  
  173.     sunriseLocalHours: function(gmt) {
  174.         return this.hoursRange( gmt + this.sunriseUtcHours() );
  175.     },
  176.  
  177.     sunsetLocalHours: function(gmt) {
  178.         return this.hoursRange( gmt + this.sunsetUtcHours() );
  179.     },
  180.  
  181.     isDaylight: function( utcCurrentHours ) {
  182.         var sunriseHours = this.sunriseUtcHours();
  183.         var sunsetHours = this.sunsetUtcHours();
  184.  
  185.         //print( "rise", sunriseHours );
  186.         //print( "set", sunsetHours );
  187.  
  188.         if ( sunsetHours < sunriseHours ) {
  189.             // Either the sunrise or sunset time is for tomorrow
  190.             if ( utcCurrentHours > sunriseHours ) {
  191.                 return true;
  192.             } else if ( utcCurrentHours < sunsetHours ) {
  193.                 return true;
  194.             } else {
  195.                 return false;
  196.             }
  197.         }
  198.  
  199.         if ( utcCurrentHours >= sunriseHours ) {
  200.             return utcCurrentHours < sunsetHours;
  201.         }
  202.  
  203.         return false;
  204.     }
  205. };
  206.  
  207. function SunriseSunsetTest() {
  208.     var testcases = {
  209.         'Los Angeles': {
  210.             'year': 2011, 'month': 1, 'day': 22,
  211.             'lat': 34.05, 'lon': -118.23333333,
  212.             'tests': { // utcHours => isDaylight?
  213.                 19.6666666: true
  214.             }
  215.         },
  216.         'Berlin': {
  217.             'year': 2011, 'month': 1, 'day': 25,
  218.             'lat': 52.5, 'lon': 13.366666667,
  219.             'tests': { // utcHours => isDaylight?
  220.                 1.25: false
  221.             }
  222.         },
  223.         'Tokyo': {
  224.             'year': 2011, 'month': 1, 'day': 23,
  225.             'lat': 35+40/60, 'lon': 139+45/60,
  226.             'tests': { // utcHours => isDaylight?
  227.                 1.5: true,
  228.                 22.5: true
  229.             }
  230.         },
  231.         'New Delhi': {
  232.             'year': 2011, 'month': 1, 'day': 22,
  233.             'lat': 35+40/60, 'lon': 139+45/60,
  234.             'tests': { // utcHours => isDaylight?
  235.             }
  236.         }
  237.     };
  238.  
  239.     var tests_run = 0;
  240.     var tests_failed = 0;
  241.  
  242.     for ( var city_name in testcases ) {
  243.         var city = testcases[ city_name ];
  244.         var ss = new SunriseSunset( city.year, city.month, city.day, city.lat, city.lon );
  245.         for ( var t in city.tests ) {
  246.             var expected = city.tests[t];
  247.             var result = ss.isDaylight( t );
  248.             var passed = result === expected;
  249.  
  250.             tests_run++;
  251.             if ( ! passed ) tests_failed++;
  252.            
  253.             //print( city_name, t, "passed:", passed );
  254.         }
  255.     }
  256.  
  257.     //print( "tests: " + tests_run, "failed: " + tests_failed );
  258. }
Advertisement
Add Comment
Please, Sign In to add comment