-
-
Save ruiokada/b28076d4911820ddcbbc to your computer and use it in GitHub Desktop.
/** | |
* Calculates today's sunrise and sunset hours in local time (or in the given tz) for the given latitude, longitude. | |
* The tz parameter is mainly for the possible circumstance that your system timezone does not match the location | |
* you are currently at. | |
* | |
* Computations are based on the formulas found in: | |
* https://en.wikipedia.org/wiki/Julian_day#Converting_Julian_or_Gregorian_calendar_date_to_Julian_Day_Number | |
* https://en.wikipedia.org/wiki/Sunrise_equation#Complete_calculation_on_Earth | |
* | |
* @method suntimes | |
* @param {Float} lat Latitude of location (South is negative) | |
* @param {Float} lng Longitude of location (West is negative) | |
* @param {Integer} tz Timezone hour offset. e.g. Pacific/Los Angeles Standard Time is -8 (Optional, defaults to system timezone) | |
* @return {Array} Returns an array of length 2 with the sunrise and sunset times as floats on 24-hour time. | |
* e.g. 6.5 is 6:30am, 23.2 is 11:12pm, 0.3 is 12:18am | |
* Returns an array with [null, -1] if the sun never rises, and [-1, null] if the sun never sets. | |
* | |
* ### LICENSING ### | |
* | |
* This code contains information derived from Wikipedia content licensed under | |
* the Creative Commons Attribution-ShareAlike License. As such, this code | |
* is distributed under the GPLv3 license: | |
* | |
* This program is free software: you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License as published by | |
* the Free Software Foundation, either version 3 of the License, or | |
* (at your option) any later version. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* You should have received a copy of the GNU General Public License | |
* along with this program. If not, see <https://www.gnu.org/licenses/>. | |
*/ | |
function suntimes(lat, lng, tz) { | |
var d = new Date(); | |
var radians = Math.PI / 180.0; | |
var degrees = 180.0 / Math.PI; | |
var a = Math.floor((14 - (d.getMonth() + 1.0)) / 12) | |
var y = d.getFullYear() + 4800 - a; | |
var m = (d.getMonth() + 1) + 12 * a - 3; | |
var j_day = d.getDate() + Math.floor((153 * m + 2)/5) + 365 * y + Math.floor(y/4) - Math.floor(y/100) + Math.floor(y/400) - 32045; | |
var n_star = j_day - 2451545.0009 - lng / 360.0; | |
var n = Math.floor(n_star + 0.5); | |
var solar_noon = 2451545.0009 - lng / 360.0 + n; | |
var M = 356.0470 + 0.9856002585 * n; | |
var C = 1.9148 * Math.sin( M * radians ) + 0.02 * Math.sin( 2 * M * radians ) + 0.0003 * Math.sin( 3 * M * radians ); | |
var L = ( M + 102.9372 + C + 180 ) % 360; | |
var j_transit = solar_noon + 0.0053 * Math.sin( M * radians) - 0.0069 * Math.sin( 2 * L * radians ); | |
var D = Math.asin( Math.sin( L * radians ) * Math.sin( 23.45 * radians ) ) * degrees; | |
var cos_omega = ( Math.sin(-0.83 * radians) - Math.sin( lat * radians ) * Math.sin( D * radians ) ) / ( Math.cos( lat * radians ) * Math.cos( D * radians ) ); | |
// sun never rises | |
if( cos_omega > 1) | |
return [null, -1]; | |
// sun never sets | |
if( cos_omega < -1 ) | |
return [-1, null]; | |
// get Julian dates of sunrise/sunset | |
var omega = Math.acos( cos_omega ) * degrees; | |
var j_set = j_transit + omega / 360.0; | |
var j_rise = j_transit - omega / 360.0; | |
/* | |
* get sunrise and sunset times in UTC | |
* Check section "Finding Julian date given Julian day number and time of | |
* day" on wikipedia for where the extra "+ 12" comes from. | |
*/ | |
var utc_time_set = 24 * (j_set - j_day) + 12; | |
var utc_time_rise = 24 * (j_rise - j_day) + 12; | |
var tz_offset = tz === undefined ? -1 * d.getTimezoneOffset() / 60 : tz; | |
var local_rise = (utc_time_rise + tz_offset) % 24; | |
var local_set = (utc_time_set + tz_offset) % 24; | |
return [local_rise, local_set]; | |
} |
That's great, I am sure not all people want to use it in same use case but if anyone did they would see my comment no need to change your code.
Sorry if this is a silly question but how do I convert the output into a readable time?
@PHDPeter Good question, I can answer it only partially. I forgot to specify that the output gives the decimal "hour of the day" of the sunrise and sunset times (i.e. a decimal number between 0 and 24). For example, 6.5 is 6:30am, 23.2 is 11:12pm, and 0.3 is 12:18am. Getting the hour is the floor of this decimal number and the minute is ((decimal hour) - floor(decimal hour)) * 60
. So something like this:
let times = suntimes(input_lat, input_lng);
let sunrise_hour = Math.floor(times[0]);
let sunrise_minute = (times[0] - Math.floor(times[0])) * 60;
Then you can do what you need with that information.
I saw your docs on tz
:
* @param {Integer} tz Timezone hour offset. e.g. Pacific/Los Angeles is -8 (Optional, defaults to system timezone)
And I'm in LA and when I give it -8
as a parameter it gives a different result. Seems to be because (new Date()).getTimezoneOffset()/60
is 7 and not -8. I'm guessing the 1hr difference is daylight savings and the negative vs positive is because we're UTC-8 but we're 8 (now 7) hours behind)
I saw your docs on
tz
:
* @param {Integer} tz Timezone hour offset. e.g. Pacific/Los Angeles is -8 (Optional, defaults to system timezone)
And I'm in LA and when I give it
-8
as a parameter it gives a different result. Seems to be because(new Date()).getTimezoneOffset()/60
is 7 and not -8. I'm guessing the 1hr difference is daylight savings and the negative vs positive is because we're UTC-8 but we're 8 (now 7) hours behind)
Thanks for mentioning this. I have specified that -8 is PST in the docs.
@Yahia20 Thanks for the correction. I have added your fix for the tz offset. I don't quite remember what I was using this script for but I wanted to be able to compute suntimes given any latitude/longitude and not the user's geolocation data; I don't think you can create arbitary geolocation data given any latitude/longitude. Though, feel free to modify the script so it suits your needs.