UNPKG

solar-calc

Version:

A sunrise/sunset/moonrise/moonset calculator

293 lines (252 loc) 8.8 kB
"use strict"; var _createClass = (function () { function defineProperties(target, props) { for (var key in props) { var prop = props[key]; prop.configurable = true; if (prop.value) prop.writable = true; } Object.defineProperties(target, props); } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; var Sun = (function () { function Sun(date, latitude, longitude) { _classCallCheck(this, Sun); this.date = date; this.latitude = latitude; this.longitude = longitude; this.julianDate = getJD(date); } _createClass(Sun, { solarNoon: { get: function () { return calcSolNoon(this.julianDate, this.longitude, this.date); } }, timeAtAngle: { value: function timeAtAngle(angle, rising) { return calcSunriseSet(rising, angle, this.julianDate, this.date, this.latitude, this.longitude); } } }); return Sun; })(); var formatDate = function formatDate(date, minutes) { var seconds = (minutes - Math.floor(minutes)) * 60; return new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), 0, minutes, seconds)); }; function calcTimeJulianCent(jd) { var T = (jd - 2451545) / 36525; return T; } function isLeapYear(yr) { return yr % 4 === 0 && yr % 100 !== 0 || yr % 400 === 0; } function calcDoyFromJD(jd) { var z = Math.floor(jd + 0.5); var f = jd + 0.5 - z; var A; if (z < 2299161) { A = z; } else { var alpha = Math.floor((z - 1867216.25) / 36524.25); A = z + 1 + alpha - Math.floor(alpha / 4); } var B = A + 1524; var C = Math.floor((B - 122.1) / 365.25); var D = Math.floor(365.25 * C); var E = Math.floor((B - D) / 30.6001); var day = B - D - Math.floor(30.6001 * E) + f; var month = E < 14 ? E - 1 : E - 13; var year = month > 2 ? C - 4716 : C - 4715; var k = isLeapYear(year) ? 1 : 2; var doy = Math.floor(275 * month / 9) - k * Math.floor((month + 9) / 12) + day - 30; return doy; } function radToDeg(angleRad) { return 180 * angleRad / Math.PI; } function degToRad(angleDeg) { return Math.PI * angleDeg / 180; } function calcGeomMeanLongSun(t) { var L0 = 280.46646 + t * (36000.76983 + t * 0.0003032); while (L0 > 360) { L0 -= 360; } while (L0 < 0) { L0 += 360; } return L0; // in degrees } function calcGeomMeanAnomalySun(t) { var M = 357.52911 + t * (35999.05029 - 0.0001537 * t); return M; // in degrees } function calcEccentricityEarthOrbit(t) { var e = 0.016708634 - t * (0.000042037 + 1.267e-7 * t); return e; // unitless } function calcSunEqOfCenter(t) { var m = calcGeomMeanAnomalySun(t); var mrad = degToRad(m); var sinm = Math.sin(mrad); var sin2m = Math.sin(mrad + mrad); var sin3m = Math.sin(mrad + mrad + mrad); var C = sinm * (1.914602 - t * (0.004817 + 0.000014 * t)) + sin2m * (0.019993 - 0.000101 * t) + sin3m * 0.000289; return C; // in degrees } function calcSunTrueLong(t) { var l0 = calcGeomMeanLongSun(t); var c = calcSunEqOfCenter(t); var O = l0 + c; return O; // in degrees } function calcSunApparentLong(t) { var o = calcSunTrueLong(t); var omega = 125.04 - 1934.136 * t; var lambda = o - 0.00569 - 0.00478 * Math.sin(degToRad(omega)); return lambda; // in degrees } function calcMeanObliquityOfEcliptic(t) { var seconds = 21.448 - t * (46.815 + t * (0.00059 - t * 0.001813)); var e0 = 23 + (26 + seconds / 60) / 60; return e0; // in degrees } function calcObliquityCorrection(t) { var e0 = calcMeanObliquityOfEcliptic(t); var omega = 125.04 - 1934.136 * t; var e = e0 + 0.00256 * Math.cos(degToRad(omega)); return e; // in degrees } function calcSunDeclination(t) { var e = calcObliquityCorrection(t); var lambda = calcSunApparentLong(t); var sint = Math.sin(degToRad(e)) * Math.sin(degToRad(lambda)); var theta = radToDeg(Math.asin(sint)); return theta; // in degrees } function calcEquationOfTime(t) { var epsilon = calcObliquityCorrection(t); var l0 = calcGeomMeanLongSun(t); var e = calcEccentricityEarthOrbit(t); var m = calcGeomMeanAnomalySun(t); var y = Math.tan(degToRad(epsilon) / 2); y *= y; var sin2l0 = Math.sin(2 * degToRad(l0)); var sinm = Math.sin(degToRad(m)); var cos2l0 = Math.cos(2 * degToRad(l0)); var sin4l0 = Math.sin(4 * degToRad(l0)); var sin2m = Math.sin(2 * degToRad(m)); var Etime = y * sin2l0 - 2 * e * sinm + 4 * e * y * sinm * cos2l0 - 0.5 * y * y * sin4l0 - 1.25 * e * e * sin2m; return radToDeg(Etime) * 4; // in minutes of time } function calcHourAngle(angle, lat, solarDec) { var latRad = degToRad(lat); var sdRad = degToRad(solarDec); var HAarg = Math.cos(degToRad(90 + angle)) / (Math.cos(latRad) * Math.cos(sdRad)) - Math.tan(latRad) * Math.tan(sdRad); var HA = Math.acos(HAarg); return HA; // in radians (for sunset, use -HA) } function isNumber(inputVal) { var oneDecimal = false; var inputStr = "" + inputVal; for (var i = 0; i < inputStr.length; i++) { var oneChar = inputStr.charAt(i); if (i === 0 && (oneChar === "-" || oneChar === "+")) { continue; } if (oneChar === "." && !oneDecimal) { oneDecimal = true; continue; } if (oneChar < "0" || oneChar > "9") { return false; } } return true; } function getJD(date) { var year = date.getFullYear(); var month = date.getMonth() + 1; var day = date.getDate(); var A = Math.floor(year / 100); var B = 2 - A + Math.floor(A / 4); var JD = Math.floor(365.25 * (year + 4716)) + Math.floor(30.6001 * (month + 1)) + day + B - 1524.5; return JD; } function calcSolNoon(jd, longitude, date) { var tnoon = calcTimeJulianCent(jd - longitude / 360); var eqTime = calcEquationOfTime(tnoon); var solNoonOffset = 720 - longitude * 4 - eqTime; // in minutes var newt = calcTimeJulianCent(jd + solNoonOffset / 1440); eqTime = calcEquationOfTime(newt); var solNoonLocal = 720 - longitude * 4 - eqTime; // in minutes while (solNoonLocal < 0) { solNoonLocal += 1440; } while (solNoonLocal >= 1440) { solNoonLocal -= 1440; } return formatDate(date, solNoonLocal); // return timeString(solNoonLocal, 3); } function dayString(jd) { if (jd < 900000 || jd > 2817000) { return "error"; } else { var z = Math.floor(jd + 0.5); var f = jd + 0.5 - z; var A; if (z < 2299161) { A = z; } else { var alpha = Math.floor((z - 1867216.25) / 36524.25); A = z + 1 + alpha - Math.floor(alpha / 4); } var B = A + 1524; var C = Math.floor((B - 122.1) / 365.25); var D = Math.floor(365.25 * C); var E = Math.floor((B - D) / 30.6001); var day = B - D - Math.floor(30.6001 * E) + f; var month = E < 14 ? E - 1 : E - 13; var year = month > 2 ? C - 4716 : C - 4715; return new Date(Date.UTC(year, month - 1, day, 0, 0, 0)); } } function calcSunriseSetUTC(rise, angle, JD, latitude, longitude) { var t = calcTimeJulianCent(JD); var eqTime = calcEquationOfTime(t); var solarDec = calcSunDeclination(t); var hourAngle = calcHourAngle(angle, latitude, solarDec); //alert("HA = " + radToDeg(hourAngle)); if (!rise) hourAngle = -hourAngle; var delta = longitude + radToDeg(hourAngle); var timeUTC = 720 - 4 * delta - eqTime; // in minutes return timeUTC; } function calcSunriseSet(rise, angle, JD, date, latitude, longitude) // rise = 1 for sunrise, 0 for sunset { var timeUTC = calcSunriseSetUTC(rise, angle, JD, latitude, longitude); var newTimeUTC = calcSunriseSetUTC(rise, angle, JD + timeUTC / 1440, latitude, longitude); if (isNumber(newTimeUTC)) { return formatDate(date, newTimeUTC); } else { // no sunrise/set found var doy = calcDoyFromJD(JD); var jdy; if (latitude > 66.4 && doy > 79 && doy < 267 || latitude < -66.4 && (doy < 83 || doy > 263)) { //previous sunrise/next sunset jdy = calcJDofNextPrevRiseSet(!rise, rise, angle, JD, latitude, longitude); return dayString(jdy); } else { //previous sunset/next sunrise jdy = calcJDofNextPrevRiseSet(rise, rise, angle, JD, latitude, longitude); return dayString(jdy); } } } function calcJDofNextPrevRiseSet(next, rise, type, JD, latitude, longitude) { var julianday = JD; var increment = next ? 1 : -1; var time = calcSunriseSetUTC(rise, type, julianday, latitude, longitude); while (!isNumber(time)) { julianday += increment; time = calcSunriseSetUTC(rise, type, julianday, latitude, longitude); } return julianday; } module.exports = Sun;