@litejs/sun 26.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +66 -0
  2. package/package.json +26 -0
  3. package/sun.js +119 -0
package/README.md ADDED
@@ -0,0 +1,66 @@
1
+
2
+ [1]: https://badgen.net/coveralls/c/github/litejs/sun
3
+ [2]: https://coveralls.io/r/litejs/sun
4
+ [3]: https://packagephobia.now.sh/badge?p=@litejs/sun
5
+ [4]: https://packagephobia.now.sh/result?p=@litejs/sun
6
+ [5]: https://badgen.net/badge/icon/Buy%20Me%20A%20Tea/orange?icon=kofi&label
7
+ [6]: https://www.buymeacoffee.com/lauriro
8
+
9
+
10
+ LiteJS Sun – [![Coverage][1]][2] [![Size][3]][4] [![Buy Me A Tea][5]][6]
11
+ ==========
12
+
13
+ Sun position and timing calculations based on NOAA solar equations.
14
+
15
+ ```sh
16
+ $ npm install @litejs/sun
17
+ ```
18
+
19
+ ```javascript
20
+ import { sun } from "@litejs/sun"
21
+
22
+ let data = sun(59.437, 24.753, "2025-03-20T12:00:00Z")
23
+ console.log("Sunrise:", data.rise.time, "Sunset:", data.set.time)
24
+ // Sunrise: 2025-03-20T04:22:24.000Z Sunset: 2025-03-20T16:35:43.000Z
25
+ console.log("Azimuth:", data.azimuth, "Elevation:", data.el)
26
+ // Azimuth: 206.16 Elevation: 28.01
27
+ ```
28
+
29
+ ## API
30
+
31
+ ### sun(lat, lon, time)
32
+
33
+ Returns an object with the following properties:
34
+
35
+ | Property | Description |
36
+ |----------------|----------------------------------------------|
37
+ | `time` | Date object for the given time |
38
+ | `decl` | Solar declination (degrees) |
39
+ | `dur` | Daylight duration (minutes) |
40
+ | `el` | Solar elevation with refraction (degrees) |
41
+ | `elTrue` | Solar elevation without refraction (degrees) |
42
+ | `eqTime` | Equation of time (minutes) |
43
+ | `hourAngle` | Solar hour angle (degrees) |
44
+ | `azimuth` | Solar azimuth (degrees, lazy) |
45
+ | `dist` | Distance to sun in AU (lazy) |
46
+ | `rightAsc` | Right ascension (degrees, lazy) |
47
+ | `noon` | Solar noon data (lazy) |
48
+ | `rise` | Sunrise data (lazy) |
49
+ | `set` | Sunset data (lazy) |
50
+
51
+ The `noon`, `rise`, and `set` getters return objects with the same structure, with `time` refined to the exact event.
52
+ During polar day or polar night, `rise` and `set` find the nearest event, which may be days or months away.
53
+ Returns `null` only at extreme latitudes (e.g., the poles) where no sunrise or sunset occurs within a year.
54
+
55
+ ## Contributing
56
+
57
+ Follow [Coding Style Guide](https://github.com/litejs/litejs/wiki/Style-Guide),
58
+ run tests `npm install; npm test`.
59
+
60
+
61
+ > Copyright (c) 2025 Lauri Rooden <lauri@rooden.ee>
62
+ [MIT License](https://litejs.com/MIT-LICENSE.txt) |
63
+ [GitHub repo](https://github.com/litejs/sun) |
64
+ [npm package](https://npmjs.org/package/@litejs/sun) |
65
+ [Buy Me A Tea][6]
66
+
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@litejs/sun",
3
+ "version": "26.2.0",
4
+ "description": "Sun position and timing calculations based on NOAA solar equations",
5
+ "license": "MIT",
6
+ "author": "Lauri Rooden <lauri@rooden.ee>",
7
+ "keywords": [
8
+ "astronomy",
9
+ "sun",
10
+ "sunrise",
11
+ "sunset",
12
+ "litejs"
13
+ ],
14
+ "main": "sun.js",
15
+ "files": [],
16
+ "scripts": {
17
+ "test": "lj t test/*.js"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "https://github.com/litejs/sun.git"
22
+ },
23
+ "devDependencies": {
24
+ "@litejs/cli": "25.1.0"
25
+ }
26
+ }
package/sun.js ADDED
@@ -0,0 +1,119 @@
1
+ !function(exports, Math) {
2
+ exports.sun = function sun(lat, lon, time, recalc) {
3
+ time = new Date(time)
4
+
5
+ var tmp
6
+ , acos = Math.acos
7
+ , cos = Math.cos
8
+ , sin = Math.sin
9
+ , tan = Math.tan
10
+ , PI = Math.PI
11
+ , rad = PI / 180
12
+ , dayMs = 86400000
13
+ , startOfDay = Math.floor(time / dayMs) * dayMs
14
+
15
+ // Julian Century
16
+ , JC = (time / dayMs - 10957.5) / 36525
17
+ , cosLat = cos(rad * lat)
18
+ , sinLat = sin(rad * lat)
19
+
20
+ // Mean Longitude of the Sun
21
+ , lonMean = rad * (280.46646 + JC * (36000.76983 + JC*0.0003032))
22
+ // Mean Anomaly of the Sun
23
+ , anomMean = rad * (357.52911 + JC * (35999.05029 - 0.0001537 * JC))
24
+ // Mean Obliquity of the Ecliptic (degrees)
25
+ , obliqMean = 23 + (26 + (21.448 - JC*(46.8150 + JC*(0.00059 - JC*0.001813)))/60)/60
26
+ // Corrected Obliquity
27
+ , obliqCorr = rad * (obliqMean + 0.00256 * cos(tmp = rad * (125.04 - 1934.136 * JC)))
28
+
29
+ // Sun's Equation of Center
30
+ , sunEqCtr = sin(anomMean) * (1.914602 - JC * (0.004817 + 0.000014 * JC)) + sin(2 * anomMean) * (0.019993 - 0.000101 * JC) + sin(3 * anomMean) * 0.000289
31
+
32
+ // Apparent Longitude of the Sun
33
+ , lonApp = lonMean + rad * (sunEqCtr - 0.00569 - 0.00478 * sin(tmp))
34
+
35
+ // Declination of the Sun
36
+ , declRad = Math.asin(sin(obliqCorr) * sin(lonApp))
37
+ , sinDecl = sin(declRad)
38
+ , cosDecl = cos(declRad)
39
+
40
+ // Eccentricity of Earth's Orbit
41
+ , earthEccent = 0.016708634 - JC * (0.000042037 + 0.0000001267 * JC)
42
+ , varY = (tmp = tan(obliqCorr / 2)) * tmp
43
+
44
+ // Equation of Time (minutes)
45
+ , eqTime = 4 * (
46
+ varY * sin(2 * lonMean) -
47
+ 2 * earthEccent * sin(anomMean) +
48
+ 4 * earthEccent * varY * sin(anomMean) * cos(2 * lonMean) -
49
+ 0.5 * varY * varY * sin(4 * lonMean) -
50
+ 1.25 * earthEccent * earthEccent * sin(2 * anomMean)
51
+ ) / rad
52
+
53
+ // Hour Angle at Sunrise (degrees)
54
+ , hourAngleRise = acos((cos(rad * 90.833) - sinLat * sinDecl) / (cosLat * cosDecl)) / rad
55
+
56
+ // True Solar Time (minutes)
57
+ , sunTime = (time / 60000 + eqTime + 4 * lon) % 1440
58
+ , hourAngle = sunTime < 0 ? sunTime / 4 + 180 : sunTime / 4 - 180
59
+
60
+ // Solar Zenith/Elevation
61
+ , cosZenith = sinLat * sinDecl + cosLat * cosDecl * cos(rad * hourAngle)
62
+ , elTrue = 90 - acos(cosZenith) / rad
63
+ // Atmospheric Refraction Correction (degrees)
64
+ , atmCorr = (
65
+ elTrue > 85 ? 0 : (tmp = tan(rad * elTrue),
66
+ elTrue > 5 ? 58.1 / tmp - 0.07 / (tmp*tmp*tmp) + 0.000086 / (tmp*tmp*tmp*tmp*tmp) :
67
+ elTrue > -0.575 ? 1735 + elTrue * (-518.2 + elTrue * (103.4 + elTrue * (-12.79 + elTrue * 0.711))) :
68
+ -20.774 / tmp
69
+ ) / 3600
70
+ )
71
+
72
+ // Solar Noon (minutes)
73
+ , noon = 720 - 4 * lon - eqTime
74
+ // Sunrise & Sunset Time (minutes)
75
+ , rise = noon - hourAngleRise * 4
76
+ , set = noon + hourAngleRise * 4
77
+
78
+ if (recalc) {
79
+ tmp = Math.round((recalc === "rise" ? rise : recalc === "set" ? set : noon) * 60) * 1000
80
+ time.setTime(startOfDay + tmp)
81
+ }
82
+
83
+ return {
84
+ time,
85
+ decl: declRad / rad,
86
+ dur: 8 * hourAngleRise, // Total Sunlight Duration (minutes)
87
+ el: elTrue + atmCorr, // Solar Elevation (Corrected for Refraction)
88
+ elTrue,
89
+ eqTime,
90
+ hourAngle,
91
+ get azimuth() {
92
+ return (tmp = acos((sinLat * cosZenith - sinDecl) / (cosLat * Math.sqrt(1 - cosZenith * cosZenith))), hourAngle > 0 ? tmp + PI : 3 * PI - tmp) * 180 / PI % 360
93
+ },
94
+ get dist() {
95
+ return 1.000001018 * (1 - earthEccent * earthEccent) / (1 + earthEccent * cos(anomMean + rad * sunEqCtr)) // Distance to Sun (Astronomical Units)
96
+ },
97
+ get rightAsc() {
98
+ return Math.atan2(cos(obliqCorr) * sin(lonApp), cos(lonApp)) / rad // Right Ascension of the Sun (degrees)
99
+ },
100
+ get noon() {
101
+ return findNext("noon", noon, -1)
102
+ },
103
+ get rise() {
104
+ return findNext("rise", rise, 1)
105
+ },
106
+ get set() {
107
+ return findNext("set", set, -1)
108
+ },
109
+ }
110
+
111
+ function findNext(key, minutes, inc) {
112
+ if (minutes === minutes) return sun(lat, lon, startOfDay + minutes * 60000, key)
113
+ var day = startOfDay, i = 366, d = (time - Date.UTC(time.getUTCFullYear(), 0, 0)) / dayMs
114
+ for (inc *= (lat > 66.4 && d > 79 && d < 267 || lat < -66.4 && (d < 83 || d > 263)) ? -dayMs : dayMs; i--; )
115
+ if ((d = sun(lat, lon, day += inc)).dur === d.dur) return d[key]
116
+ return null
117
+ }
118
+ }
119
+ }(this, Math) // jshint ignore:line