UNPKG

@hebcal/solar-calc

Version:

A sunrise/sunset/moonrise/moonset calculator - fork

223 lines (180 loc) 6.07 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Sun = void 0; class Sun { constructor(date, latitude, longitude) { this.date = date; this.latitude = latitude; this.longitude = longitude; this.julianDate = getJD(date); } get solarNoon() { return calcSolNoon(this.julianDate, this.longitude, this.date); } timeAtAngle(angle, rising) { return calcSunriseSet(rising, angle, this.julianDate, this.date, this.latitude, this.longitude); } } exports.Sun = Sun; function formatDate(date, minutes) { const seconds = (minutes - Math.floor(minutes)) * 60; return new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), 0, minutes, seconds)); } function calcTimeJulianCent(jd) { const T = (jd - 2451545.0) / 36525.0; return T; } function radToDeg(angleRad) { return 180.0 * angleRad / Math.PI; } function degToRad(angleDeg) { return Math.PI * angleDeg / 180.0; } function calcGeomMeanLongSun(t) { let L0 = 280.46646 + t * (36000.76983 + t * 0.0003032); while (L0 > 360.0) { L0 -= 360.0; } while (L0 < 0.0) { L0 += 360.0; } return L0; // in degrees } function calcGeomMeanAnomalySun(t) { const M = 357.52911 + t * (35999.05029 - 0.0001537 * t); return M; // in degrees } function calcEccentricityEarthOrbit(t) { const e = 0.016708634 - t * (0.000042037 + 0.0000001267 * t); return e; // unitless } function calcSunEqOfCenter(t) { const m = calcGeomMeanAnomalySun(t); const mrad = degToRad(m); const sinm = Math.sin(mrad); const sin2m = Math.sin(mrad + mrad); const sin3m = Math.sin(mrad + mrad + mrad); const 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) { const l0 = calcGeomMeanLongSun(t); const c = calcSunEqOfCenter(t); const O = l0 + c; return O; // in degrees } function calcSunApparentLong(t) { const o = calcSunTrueLong(t); const omega = 125.04 - 1934.136 * t; const lambda = o - 0.00569 - 0.00478 * Math.sin(degToRad(omega)); return lambda; // in degrees } function calcMeanObliquityOfEcliptic(t) { const seconds = 21.448 - t * (46.8150 + t * (0.00059 - t * 0.001813)); const e0 = 23.0 + (26.0 + seconds / 60.0) / 60.0; return e0; // in degrees } function calcObliquityCorrection(t) { const e0 = calcMeanObliquityOfEcliptic(t); const omega = 125.04 - 1934.136 * t; const e = e0 + 0.00256 * Math.cos(degToRad(omega)); return e; // in degrees } function calcSunDeclination(t) { const e = calcObliquityCorrection(t); const lambda = calcSunApparentLong(t); const sint = Math.sin(degToRad(e)) * Math.sin(degToRad(lambda)); const theta = radToDeg(Math.asin(sint)); return theta; // in degrees } function calcEquationOfTime(t) { const epsilon = calcObliquityCorrection(t); const l0 = calcGeomMeanLongSun(t); const e = calcEccentricityEarthOrbit(t); const m = calcGeomMeanAnomalySun(t); let y = Math.tan(degToRad(epsilon) / 2.0); y *= y; const sin2l0 = Math.sin(2.0 * degToRad(l0)); const sinm = Math.sin(degToRad(m)); const cos2l0 = Math.cos(2.0 * degToRad(l0)); const sin4l0 = Math.sin(4.0 * degToRad(l0)); const sin2m = Math.sin(2.0 * degToRad(m)); const Etime = y * sin2l0 - 2.0 * e * sinm + 4.0 * e * y * sinm * cos2l0 - 0.5 * y * y * sin4l0 - 1.25 * e * e * sin2m; return radToDeg(Etime) * 4.0; // in minutes of time } function calcHourAngle(angle, lat, solarDec) { const latRad = degToRad(lat); const sdRad = degToRad(solarDec); const HAarg = Math.cos(degToRad(90 + angle)) / (Math.cos(latRad) * Math.cos(sdRad)) - Math.tan(latRad) * Math.tan(sdRad); const HA = Math.acos(HAarg); return HA; // in radians (for sunset, use -HA) } function isNumber(inputVal) { let oneDecimal = false; const inputStr = `${inputVal}`; for (let i = 0; i < inputStr.length; i++) { const 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) { let year = date.getFullYear(); let month = date.getMonth() + 1; const day = date.getDate(); if (month < 3) { year--; month += 12; } const A = Math.floor(year / 100); const B = 2 - A + Math.floor(A / 4); const JD = Math.floor(365.25 * (year + 4716)) + Math.floor(30.6001 * (month + 1)) + day + B - 1524.5; return JD; } function calcSolNoon(jd, longitude, date) { const tnoon = calcTimeJulianCent(jd - longitude / 360.0); let eqTime = calcEquationOfTime(tnoon); const solNoonOffset = 720.0 - longitude * 4 - eqTime; // in minutes const newt = calcTimeJulianCent(jd + solNoonOffset / 1440.0); eqTime = calcEquationOfTime(newt); let solNoonLocal = 720 - longitude * 4 - eqTime; // in minutes while (solNoonLocal < 0.0) { solNoonLocal += 1440.0; } while (solNoonLocal >= 1440.0) { solNoonLocal -= 1440.0; } return formatDate(date, solNoonLocal); // return timeString(solNoonLocal, 3); } function calcSunriseSetUTC(rise, angle, JD, latitude, longitude) { const t = calcTimeJulianCent(JD); const eqTime = calcEquationOfTime(t); const solarDec = calcSunDeclination(t); let hourAngle = calcHourAngle(angle, latitude, solarDec); //alert("HA = " + radToDeg(hourAngle)); if (!rise) hourAngle = -hourAngle; const delta = longitude + radToDeg(hourAngle); const timeUTC = 720 - 4.0 * delta - eqTime; // in minutes return timeUTC; } function calcSunriseSet(rise, angle, JD, date, latitude, longitude) // rise = 1 for sunrise, 0 for sunset { const timeUTC = calcSunriseSetUTC(rise, angle, JD, latitude, longitude); const newTimeUTC = calcSunriseSetUTC(rise, angle, JD + timeUTC / 1440.0, latitude, longitude); if (isNumber(newTimeUTC)) { return formatDate(date, newTimeUTC); } else { // no sunrise/set found return new Date(NaN); } }