UNPKG

solar-time

Version:

This library provides functions to calculate local solar time, also known as local apparent time, based on a given location and date.

89 lines (88 loc) 3.93 kB
function y(t) { const n = t.getUTCFullYear(), e = t.getUTCMonth(), a = t.getUTCDate(), s = Date.UTC(n, 0, 0), o = Date.UTC(n, e, a) - s; return Math.floor(o / (1e3 * 60 * 60 * 24)); } function l(t) { if (t.endsWith("Z")) return 0; const n = t.match(/([+-])(\d{2}):(\d{2})$/); if (!n) return 0; const e = n[1] === "+" ? 1 : -1, a = parseInt(n[2], 10), s = parseInt(n[3], 10); return e * (a + s / 60); } function E(t) { const n = new Date(t), e = l(t), a = n.getTime() + e * 60 * 60 * 1e3, s = new Date(a), c = new Date(Date.UTC(s.getUTCFullYear(), s.getUTCMonth(), s.getUTCDate(), 0, 0, 0, 0)); return e !== 0 ? I(c, e) : c.toISOString(); } function f(t, n, e) { const a = new Date(t), s = new Date(a.getTime() + n * 60 * 1e3); return e !== 0 ? I(s, e) : s.toISOString(); } function I(t, n) { const e = new Date(t.getTime() + n * 60 * 60 * 1e3), a = e.getUTCFullYear(), s = String(e.getUTCMonth() + 1).padStart(2, "0"), c = String(e.getUTCDate()).padStart(2, "0"), o = String(e.getUTCHours()).padStart(2, "0"), r = String(e.getUTCMinutes()).padStart(2, "0"), i = String(e.getUTCSeconds()).padStart(2, "0"), M = n >= 0 ? "+" : "-", u = Math.abs(n), h = String(Math.floor(u)).padStart(2, "0"), d = String(Math.round(u % 1 * 60)).padStart(2, "0"); return `${a}-${s}-${c}T${o}:${r}:${i}${M}${h}:${d}`; } function L(t) { const n = new Date(t), e = l(t); let s = n.getUTCHours() * 60 + n.getUTCMinutes() + n.getUTCSeconds() / 60 + e * 60; return s < 0 && (s += 1440), s >= 1440 && (s -= 1440), s; } function R(t) { if (typeof t != "number" || Number.isNaN(t)) throw new Error("Longitude must be a valid number"); if (t < -180 || t > 180) throw new Error("Longitude must be between -180 and 180 degrees"); } function z(t) { if (typeof t != "string") throw new Error("DateTime must be an ISO 8601 string"); const n = new Date(t); if (Number.isNaN(n.getTime())) throw new Error("Invalid ISO 8601 datetime string"); } const Y = (t, n) => { z(t), R(n); const e = new Date(t), a = l(t), s = 15 * a, c = y(e), o = 2 * Math.PI * (c - 1) / 365, r = 1440 / (2 * Math.PI) * (75e-7 + 1868e-6 * Math.cos(o) - 0.032077 * Math.sin(o) - 0.014615 * Math.cos(2 * o) - 0.040849 * Math.sin(2 * o)), M = (6918e-6 - 0.399912 * Math.cos(o) + 0.070257 * Math.sin(o) - 6758e-6 * Math.cos(2 * o) + 907e-6 * Math.sin(2 * o) - 2697e-6 * Math.cos(3 * o) + 148e-5 * Math.sin(3 * o)) * (180 / Math.PI), u = 360 / 365 * (c - 1), h = 4 * (n - s) + r; return { LST: f(t, h, a), // Preserve timezone from input TC: h, EoT: r, B: u, LSTM: s, declination: M }; }; function A(t) { if (typeof t != "number" || Number.isNaN(t)) throw new Error("Latitude must be a valid number"); if (t < -90 || t > 90) throw new Error("Latitude must be between -90 and 90 degrees"); } const x = (t, n, e) => { A(n); const a = Y(t, e), { declination: s, EoT: c } = a, o = l(t), r = n * (Math.PI / 180), i = s * (Math.PI / 180), M = 90.833 * (Math.PI / 180), u = (Math.cos(M) - Math.sin(r) * Math.sin(i)) / (Math.cos(r) * Math.cos(i)), h = E(t); let d = null, S = null; if (Math.abs(u) <= 1) { const b = Math.acos(u) * (180 / Math.PI), $ = 720 - 4 * (e + b) - c, v = 720 - 4 * (e - b) - c; d = f(h, $, o), S = f(h, v, o); } const p = 720 - 4 * e - c, D = f(h, p, o); let g = (L(t) + a.TC) / 60; g < 0 && (g += 24), g >= 24 && (g -= 24); const w = 15 * (g - 12) * (Math.PI / 180), C = Math.sin(r) * Math.sin(i) + Math.cos(r) * Math.cos(i) * Math.cos(w), T = Math.asin(C), U = T * (180 / Math.PI), O = 90 - U, N = -Math.sin(w) * Math.cos(i) / Math.cos(T), P = (Math.sin(i) - Math.sin(r) * C) / (Math.cos(r) * Math.cos(T)); let m = Math.atan2(N, P) * (180 / Math.PI); return m < 0 && (m += 360), { sunrise: d, sunset: S, solarNoon: D, azimuth: m, elevation: U, zenith: O }; }; export { Y as getSolarTime, x as getSunPosition };