@typescriptify/sweph 1.0.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 (211) hide show
  1. package/README.md +422 -0
  2. package/ephe/semo_18.se1 +0 -0
  3. package/ephe/sepl_18.se1 +0 -0
  4. package/originalCode/.eslintrc.json +124 -0
  5. package/originalCode/.gitattributes +2 -0
  6. package/originalCode/.github/FUNDING.yml +5 -0
  7. package/originalCode/.github/workflows/test.yml +35 -0
  8. package/originalCode/LICENSE +840 -0
  9. package/originalCode/README.md +91 -0
  10. package/originalCode/binding.gyp +41 -0
  11. package/originalCode/constants.js +366 -0
  12. package/originalCode/docs.gif +0 -0
  13. package/originalCode/index.d.ts +5115 -0
  14. package/originalCode/index.js +7 -0
  15. package/originalCode/index.mjs +109 -0
  16. package/originalCode/package.json +55 -0
  17. package/originalCode/src/functions/azalt.cpp +39 -0
  18. package/originalCode/src/functions/azalt_rev.cpp +35 -0
  19. package/originalCode/src/functions/calc.cpp +29 -0
  20. package/originalCode/src/functions/calc_pctr.cpp +31 -0
  21. package/originalCode/src/functions/calc_ut.cpp +29 -0
  22. package/originalCode/src/functions/close.cpp +6 -0
  23. package/originalCode/src/functions/cotrans.cpp +26 -0
  24. package/originalCode/src/functions/cotrans_sp.cpp +26 -0
  25. package/originalCode/src/functions/cs2degstr.cpp +19 -0
  26. package/originalCode/src/functions/cs2lonlatstr.cpp +23 -0
  27. package/originalCode/src/functions/cs2timestr.cpp +23 -0
  28. package/originalCode/src/functions/csnorm.cpp +15 -0
  29. package/originalCode/src/functions/csroundsec.cpp +15 -0
  30. package/originalCode/src/functions/d2l.cpp +15 -0
  31. package/originalCode/src/functions/date_conversion.cpp +30 -0
  32. package/originalCode/src/functions/day_of_week.cpp +15 -0
  33. package/originalCode/src/functions/degnorm.cpp +15 -0
  34. package/originalCode/src/functions/deltat.cpp +15 -0
  35. package/originalCode/src/functions/deltat_ex.cpp +24 -0
  36. package/originalCode/src/functions/difcs2n.cpp +19 -0
  37. package/originalCode/src/functions/difcsn.cpp +19 -0
  38. package/originalCode/src/functions/difdeg2n.cpp +19 -0
  39. package/originalCode/src/functions/difdegn.cpp +19 -0
  40. package/originalCode/src/functions/fixstar.cpp +32 -0
  41. package/originalCode/src/functions/fixstar2.cpp +32 -0
  42. package/originalCode/src/functions/fixstar2_mag.cpp +28 -0
  43. package/originalCode/src/functions/fixstar2_ut.cpp +32 -0
  44. package/originalCode/src/functions/fixstar_mag.cpp +28 -0
  45. package/originalCode/src/functions/fixstar_ut.cpp +32 -0
  46. package/originalCode/src/functions/gauquelin_sector.cpp +44 -0
  47. package/originalCode/src/functions/get_ayanamsa.cpp +15 -0
  48. package/originalCode/src/functions/get_ayanamsa_ex.cpp +27 -0
  49. package/originalCode/src/functions/get_ayanamsa_ex_ut.cpp +27 -0
  50. package/originalCode/src/functions/get_ayanamsa_name.cpp +19 -0
  51. package/originalCode/src/functions/get_ayanamsa_ut.cpp +15 -0
  52. package/originalCode/src/functions/get_current_file_data.cpp +28 -0
  53. package/originalCode/src/functions/get_library_path.cpp +8 -0
  54. package/originalCode/src/functions/get_orbital_elements.cpp +29 -0
  55. package/originalCode/src/functions/get_planet_name.cpp +19 -0
  56. package/originalCode/src/functions/get_tid_acc.cpp +7 -0
  57. package/originalCode/src/functions/heliacal_pheno_ut.cpp +52 -0
  58. package/originalCode/src/functions/heliacal_ut.cpp +52 -0
  59. package/originalCode/src/functions/helio_cross.cpp +33 -0
  60. package/originalCode/src/functions/helio_cross_ut.cpp +33 -0
  61. package/originalCode/src/functions/house_name.cpp +20 -0
  62. package/originalCode/src/functions/house_pos.cpp +36 -0
  63. package/originalCode/src/functions/houses.cpp +35 -0
  64. package/originalCode/src/functions/houses_armc.cpp +38 -0
  65. package/originalCode/src/functions/houses_armc_ex2.cpp +47 -0
  66. package/originalCode/src/functions/houses_ex.cpp +37 -0
  67. package/originalCode/src/functions/houses_ex2.cpp +46 -0
  68. package/originalCode/src/functions/jdet_to_utc.cpp +38 -0
  69. package/originalCode/src/functions/jdut1_to_utc.cpp +38 -0
  70. package/originalCode/src/functions/julday.cpp +25 -0
  71. package/originalCode/src/functions/lat_to_lmt.cpp +27 -0
  72. package/originalCode/src/functions/lmt_to_lat.cpp +27 -0
  73. package/originalCode/src/functions/lun_eclipse_how.cpp +34 -0
  74. package/originalCode/src/functions/lun_eclipse_when.cpp +31 -0
  75. package/originalCode/src/functions/lun_eclipse_when_loc.cpp +39 -0
  76. package/originalCode/src/functions/lun_occult_when_glob.cpp +35 -0
  77. package/originalCode/src/functions/lun_occult_when_loc.cpp +43 -0
  78. package/originalCode/src/functions/lun_occult_where.cpp +34 -0
  79. package/originalCode/src/functions/mooncross.cpp +26 -0
  80. package/originalCode/src/functions/mooncross_node.cpp +30 -0
  81. package/originalCode/src/functions/mooncross_node_ut.cpp +30 -0
  82. package/originalCode/src/functions/mooncross_ut.cpp +26 -0
  83. package/originalCode/src/functions/nod_aps.cpp +42 -0
  84. package/originalCode/src/functions/nod_aps_ut.cpp +42 -0
  85. package/originalCode/src/functions/orbit_max_min_true_distance.cpp +37 -0
  86. package/originalCode/src/functions/pheno.cpp +29 -0
  87. package/originalCode/src/functions/pheno_ut.cpp +29 -0
  88. package/originalCode/src/functions/radnorm.cpp +15 -0
  89. package/originalCode/src/functions/refrac.cpp +23 -0
  90. package/originalCode/src/functions/refrac_extended.cpp +32 -0
  91. package/originalCode/src/functions/revjul.cpp +33 -0
  92. package/originalCode/src/functions/rise_trans.cpp +44 -0
  93. package/originalCode/src/functions/rise_trans_true_hor.cpp +46 -0
  94. package/originalCode/src/functions/set_delta_t_userdef.cpp +14 -0
  95. package/originalCode/src/functions/set_ephe_path.cpp +14 -0
  96. package/originalCode/src/functions/set_jpl_file.cpp +14 -0
  97. package/originalCode/src/functions/set_sid_mode.cpp +20 -0
  98. package/originalCode/src/functions/set_tid_acc.cpp +14 -0
  99. package/originalCode/src/functions/set_topo.cpp +20 -0
  100. package/originalCode/src/functions/sidtime.cpp +15 -0
  101. package/originalCode/src/functions/sidtime0.cpp +21 -0
  102. package/originalCode/src/functions/sol_eclipse_how.cpp +34 -0
  103. package/originalCode/src/functions/sol_eclipse_when_glob.cpp +31 -0
  104. package/originalCode/src/functions/sol_eclipse_when_loc.cpp +39 -0
  105. package/originalCode/src/functions/sol_eclipse_where.cpp +30 -0
  106. package/originalCode/src/functions/solcross.cpp +26 -0
  107. package/originalCode/src/functions/solcross_ut.cpp +26 -0
  108. package/originalCode/src/functions/split_deg.cpp +35 -0
  109. package/originalCode/src/functions/time_equ.cpp +25 -0
  110. package/originalCode/src/functions/utc_time_zone.cpp +48 -0
  111. package/originalCode/src/functions/utc_to_jd.cpp +37 -0
  112. package/originalCode/src/functions/version.cpp +8 -0
  113. package/originalCode/src/functions/vis_limit_mag.cpp +50 -0
  114. package/originalCode/src/sweph.cpp +150 -0
  115. package/originalCode/src/sweph.h +119 -0
  116. package/originalCode/swisseph/swecl.c +6428 -0
  117. package/originalCode/swisseph/swedate.c +588 -0
  118. package/originalCode/swisseph/swedate.h +81 -0
  119. package/originalCode/swisseph/swehel.c +3511 -0
  120. package/originalCode/swisseph/swehouse.c +3143 -0
  121. package/originalCode/swisseph/swehouse.h +98 -0
  122. package/originalCode/swisseph/swejpl.c +958 -0
  123. package/originalCode/swisseph/swejpl.h +103 -0
  124. package/originalCode/swisseph/swemmoon.c +1930 -0
  125. package/originalCode/swisseph/swemplan.c +967 -0
  126. package/originalCode/swisseph/swemptab.h +10640 -0
  127. package/originalCode/swisseph/swenut2000a.h +2819 -0
  128. package/originalCode/swisseph/sweodef.h +326 -0
  129. package/originalCode/swisseph/sweph.c +8614 -0
  130. package/originalCode/swisseph/sweph.h +849 -0
  131. package/originalCode/swisseph/swephexp.h +1020 -0
  132. package/originalCode/swisseph/swephlib.c +4634 -0
  133. package/originalCode/swisseph/swephlib.h +189 -0
  134. package/package.json +28 -0
  135. package/scripts/gen-swemptab.js +177 -0
  136. package/scripts/gen-swenut2000a.js +106 -0
  137. package/src/SwissEph/README.md +268 -0
  138. package/src/SwissEph/UseCases/Ayanamsa.md +363 -0
  139. package/src/SwissEph/UseCases/AzimuthAltitude.md +408 -0
  140. package/src/SwissEph/UseCases/CoordinateSystems.md +337 -0
  141. package/src/SwissEph/UseCases/DateAndTime.md +368 -0
  142. package/src/SwissEph/UseCases/DeltaT.md +258 -0
  143. package/src/SwissEph/UseCases/EphemerisFiles.md +338 -0
  144. package/src/SwissEph/UseCases/FixedStars.md +300 -0
  145. package/src/SwissEph/UseCases/GauquelinSectors.md +304 -0
  146. package/src/SwissEph/UseCases/HeliacalEvents.md +396 -0
  147. package/src/SwissEph/UseCases/HelioCrossings.md +325 -0
  148. package/src/SwissEph/UseCases/HousePosition.md +254 -0
  149. package/src/SwissEph/UseCases/HouseSystems.md +279 -0
  150. package/src/SwissEph/UseCases/LunarEclipse.md +326 -0
  151. package/src/SwissEph/UseCases/MeridianTransit.md +279 -0
  152. package/src/SwissEph/UseCases/MoonCrossings.md +373 -0
  153. package/src/SwissEph/UseCases/NodesAndApsides.md +307 -0
  154. package/src/SwissEph/UseCases/Occultation.md +352 -0
  155. package/src/SwissEph/UseCases/OrbitalElements.md +469 -0
  156. package/src/SwissEph/UseCases/Phenomena.md +328 -0
  157. package/src/SwissEph/UseCases/PlanetPositions.md +366 -0
  158. package/src/SwissEph/UseCases/Planetocentric.md +278 -0
  159. package/src/SwissEph/UseCases/Refraction.md +314 -0
  160. package/src/SwissEph/UseCases/RiseAndSet.md +433 -0
  161. package/src/SwissEph/UseCases/SiderealTime.md +302 -0
  162. package/src/SwissEph/UseCases/SolarEclipse.md +379 -0
  163. package/src/SwissEph/UseCases/SunCrossings.md +275 -0
  164. package/src/SwissEph/UseCases/TopocentricCorrection.md +335 -0
  165. package/src/SwissEph/errors.ts +10 -0
  166. package/src/SwissEph/index.ts +823 -0
  167. package/src/SwissEph/types.ts +291 -0
  168. package/src/constants.ts +762 -0
  169. package/src/file-reader.ts +147 -0
  170. package/src/index.ts +10 -0
  171. package/src/swecl.ts +4526 -0
  172. package/src/swedate.ts +376 -0
  173. package/src/swehel.ts +1939 -0
  174. package/src/swehouse.ts +2167 -0
  175. package/src/swejpl.ts +470 -0
  176. package/src/swemmoon.ts +1318 -0
  177. package/src/swemplan.ts +585 -0
  178. package/src/swemptab.ts +4448 -0
  179. package/src/swenut2000a.ts +2763 -0
  180. package/src/sweph.ts +3993 -0
  181. package/src/swephlib.ts +2720 -0
  182. package/src/types.ts +490 -0
  183. package/tests/c-style/ayanamsa.test.ts +63 -0
  184. package/tests/c-style/config.test.ts +96 -0
  185. package/tests/c-style/crossings.test.ts +81 -0
  186. package/tests/c-style/date-time.test.ts +114 -0
  187. package/tests/c-style/eclipses.test.ts +84 -0
  188. package/tests/c-style/fixed-stars.test.ts +66 -0
  189. package/tests/c-style/heliacal.test.ts +34 -0
  190. package/tests/c-style/houses.test.ts +135 -0
  191. package/tests/c-style/math-utils.test.ts +160 -0
  192. package/tests/c-style/orbital.test.ts +78 -0
  193. package/tests/c-style/phenomena.test.ts +42 -0
  194. package/tests/c-style/planetocentric.test.ts +26 -0
  195. package/tests/c-style/planets.test.ts +117 -0
  196. package/tests/c-style/rise-set.test.ts +71 -0
  197. package/tests/helpers.ts +21 -0
  198. package/tests/modern/ayanamsa.test.ts +47 -0
  199. package/tests/modern/calc.test.ts +113 -0
  200. package/tests/modern/config.test.ts +46 -0
  201. package/tests/modern/crossings.test.ts +45 -0
  202. package/tests/modern/eclipses.test.ts +81 -0
  203. package/tests/modern/errors.test.ts +71 -0
  204. package/tests/modern/heliacal.test.ts +30 -0
  205. package/tests/modern/houses.test.ts +87 -0
  206. package/tests/modern/orbital.test.ts +79 -0
  207. package/tests/modern/phenomena.test.ts +41 -0
  208. package/tests/modern/rise-set.test.ts +60 -0
  209. package/tests/modern/statics.test.ts +99 -0
  210. package/tests/modern/utilities.test.ts +70 -0
  211. package/tsconfig.json +20 -0
@@ -0,0 +1,433 @@
1
+ # Rise and Set
2
+
3
+ **Rise** and **set** refer to the moments when a celestial body appears above or disappears below the horizon. Sunrise and sunset are the most familiar examples, but the Moon, planets, and stars all rise and set as well due to the Earth's rotation.
4
+
5
+ Knowing when objects rise and set is fundamental to observational astronomy (you can only observe objects when they are above the horizon) and is one of the oldest astronomical calculations. It also has practical applications in daily life, agriculture, religious observances (many traditions define prayer times or holidays based on sunset/sunrise), photography (golden hour), and navigation.
6
+
7
+ The Swiss Ephemeris computes rise and set times accounting for atmospheric refraction, the apparent size of the object's disc, and the observer's geographic position. It can also compute twilight times (civil, nautical, and astronomical), which are defined by the Sun reaching specific angles below the horizon.
8
+
9
+ ---
10
+
11
+ ## Quick Example
12
+
13
+ ```typescript
14
+ import { SwissEph } from '../index';
15
+ import { SE_SUN } from '../../constants';
16
+
17
+ const swe = new SwissEph();
18
+
19
+ // Sunrise and sunset in New York on June 21, 2024
20
+ const jd = SwissEph.julianDay(2024, 6, 21, 0); // midnight UT
21
+ const nyc = { longitude: -74.006, latitude: 40.713 };
22
+
23
+ const sunrise = swe.rise(jd, SE_SUN, nyc);
24
+ const sunset = swe.set(jd, SE_SUN, nyc);
25
+
26
+ const fmt = (jd: number) => {
27
+ const d = SwissEph.fromJulianDay(jd);
28
+ const h = Math.floor(d.hour);
29
+ const m = Math.floor((d.hour - h) * 60);
30
+ return `${h}:${String(m).padStart(2,'0')} UT`;
31
+ };
32
+
33
+ console.log(`Sunrise: ${fmt(sunrise.jd)}`);
34
+ console.log(`Sunset: ${fmt(sunset.jd)}`);
35
+
36
+ swe.close();
37
+ ```
38
+
39
+ ---
40
+
41
+ ## Detailed Examples
42
+
43
+ ### Sunrise and sunset with local time conversion
44
+
45
+ The result is in UT (Universal Time). To display local time, add the timezone offset.
46
+
47
+ ```typescript
48
+ import { SwissEph } from '../index';
49
+ import { SE_SUN } from '../../constants';
50
+
51
+ const swe = new SwissEph();
52
+
53
+ // London, January 15, 2024
54
+ const jd = SwissEph.julianDay(2024, 1, 15, 0);
55
+ const london = { longitude: -0.128, latitude: 51.507 };
56
+
57
+ const sunrise = swe.rise(jd, SE_SUN, london);
58
+ const sunset = swe.set(jd, SE_SUN, london);
59
+
60
+ const fmtLocal = (jd: number, tzOffsetHours: number) => {
61
+ const d = SwissEph.fromJulianDay(jd);
62
+ let hours = d.hour + tzOffsetHours;
63
+ if (hours < 0) hours += 24;
64
+ if (hours >= 24) hours -= 24;
65
+ const h = Math.floor(hours);
66
+ const m = Math.floor((hours - h) * 60);
67
+ const s = Math.round(((hours - h) * 60 - m) * 60);
68
+ return `${h}:${String(m).padStart(2,'0')}:${String(s).padStart(2,'0')}`;
69
+ };
70
+
71
+ // London is UTC+0 in winter (GMT)
72
+ console.log(`Sunrise: ${fmtLocal(sunrise.jd, 0)} GMT`);
73
+ console.log(`Sunset: ${fmtLocal(sunset.jd, 0)} GMT`);
74
+
75
+ swe.close();
76
+ ```
77
+
78
+ ### Moonrise and moonset
79
+
80
+ The Moon rises and sets just like the Sun, but its times shift by roughly 50 minutes per day because the Moon orbits the Earth.
81
+
82
+ ```typescript
83
+ import { SwissEph } from '../index';
84
+ import { SE_MOON } from '../../constants';
85
+
86
+ const swe = new SwissEph();
87
+
88
+ const jd = SwissEph.julianDay(2024, 6, 21, 0);
89
+ const paris = { longitude: 2.352, latitude: 48.857 };
90
+
91
+ const moonrise = swe.rise(jd, SE_MOON, paris);
92
+ const moonset = swe.set(jd, SE_MOON, paris);
93
+
94
+ const fmt = (jd: number) => {
95
+ const d = SwissEph.fromJulianDay(jd);
96
+ const h = Math.floor(d.hour);
97
+ const m = Math.floor((d.hour - h) * 60);
98
+ return `${h}:${String(m).padStart(2,'0')} UT`;
99
+ };
100
+
101
+ console.log(`Moonrise: ${fmt(moonrise.jd)}`);
102
+ console.log(`Moonset: ${fmt(moonset.jd)}`);
103
+
104
+ swe.close();
105
+ ```
106
+
107
+ ### Planet rise and set
108
+
109
+ ```typescript
110
+ import { SwissEph } from '../index';
111
+ import { SE_VENUS, SE_JUPITER, SE_MARS } from '../../constants';
112
+
113
+ const swe = new SwissEph();
114
+
115
+ const jd = SwissEph.julianDay(2024, 4, 15, 0);
116
+ const sydney = { longitude: 151.209, latitude: -33.868 };
117
+
118
+ const fmt = (jd: number) => {
119
+ const d = SwissEph.fromJulianDay(jd);
120
+ const h = Math.floor(d.hour);
121
+ const m = Math.floor((d.hour - h) * 60);
122
+ return `${h}:${String(m).padStart(2,'0')} UT`;
123
+ };
124
+
125
+ const planets = [
126
+ { id: SE_VENUS, name: 'Venus' },
127
+ { id: SE_MARS, name: 'Mars' },
128
+ { id: SE_JUPITER, name: 'Jupiter' },
129
+ ];
130
+
131
+ for (const p of planets) {
132
+ const rise = swe.rise(jd, p.id, sydney);
133
+ const set = swe.set(jd, p.id, sydney);
134
+ console.log(`${p.name.padEnd(8)} rise: ${fmt(rise.jd)} set: ${fmt(set.jd)}`);
135
+ }
136
+
137
+ swe.close();
138
+ ```
139
+
140
+ ### Twilight times
141
+
142
+ Twilight is the period when the Sun is below the horizon but its light still illuminates the atmosphere. There are three standard definitions:
143
+
144
+ - **Civil twilight**: Sun is 0 to 6 degrees below the horizon. Enough light to see outdoors without artificial lighting.
145
+ - **Nautical twilight**: Sun is 6 to 12 degrees below. The horizon is still visible at sea.
146
+ - **Astronomical twilight**: Sun is 12 to 18 degrees below. The sky is dark enough for most astronomical observations.
147
+
148
+ ```typescript
149
+ import { SwissEph } from '../index';
150
+ import {
151
+ SE_SUN,
152
+ SE_BIT_CIVIL_TWILIGHT, SE_BIT_NAUTIC_TWILIGHT, SE_BIT_ASTRO_TWILIGHT,
153
+ } from '../../constants';
154
+
155
+ const swe = new SwissEph();
156
+
157
+ const jd = SwissEph.julianDay(2024, 6, 21, 0);
158
+ const berlin = { longitude: 13.405, latitude: 52.520 };
159
+
160
+ const fmt = (jd: number) => {
161
+ const d = SwissEph.fromJulianDay(jd);
162
+ const h = Math.floor(d.hour);
163
+ const m = Math.floor((d.hour - h) * 60);
164
+ return `${h}:${String(m).padStart(2,'0')} UT`;
165
+ };
166
+
167
+ // Morning twilight (when twilight begins = Sun rises past the threshold going up)
168
+ const astroBegin = swe.rise(jd, SE_SUN, berlin, { flags: SE_BIT_ASTRO_TWILIGHT });
169
+ const nauticBegin = swe.rise(jd, SE_SUN, berlin, { flags: SE_BIT_NAUTIC_TWILIGHT });
170
+ const civilBegin = swe.rise(jd, SE_SUN, berlin, { flags: SE_BIT_CIVIL_TWILIGHT });
171
+ const sunrise = swe.rise(jd, SE_SUN, berlin);
172
+
173
+ // Evening twilight (when Sun sets past the threshold going down)
174
+ const sunset = swe.set(jd, SE_SUN, berlin);
175
+ const civilEnd = swe.set(jd, SE_SUN, berlin, { flags: SE_BIT_CIVIL_TWILIGHT });
176
+ const nauticEnd = swe.set(jd, SE_SUN, berlin, { flags: SE_BIT_NAUTIC_TWILIGHT });
177
+ const astroEnd = swe.set(jd, SE_SUN, berlin, { flags: SE_BIT_ASTRO_TWILIGHT });
178
+
179
+ console.log(`Berlin, June 21, 2024:`);
180
+ console.log(` Astro twilight begins: ${fmt(astroBegin.jd)}`);
181
+ console.log(` Nautic twilight begins: ${fmt(nauticBegin.jd)}`);
182
+ console.log(` Civil twilight begins: ${fmt(civilBegin.jd)}`);
183
+ console.log(` Sunrise: ${fmt(sunrise.jd)}`);
184
+ console.log(` Sunset: ${fmt(sunset.jd)}`);
185
+ console.log(` Civil twilight ends: ${fmt(civilEnd.jd)}`);
186
+ console.log(` Nautic twilight ends: ${fmt(nauticEnd.jd)}`);
187
+ console.log(` Astro twilight ends: ${fmt(astroEnd.jd)}`);
188
+
189
+ swe.close();
190
+ ```
191
+
192
+ ### Disc center and no refraction
193
+
194
+ By default, rise/set is calculated for when the **upper limb** (top edge) of the object's disc crosses the horizon, with atmospheric refraction applied. You can change this behavior.
195
+
196
+ ```typescript
197
+ import { SwissEph } from '../index';
198
+ import {
199
+ SE_SUN,
200
+ SE_BIT_DISC_CENTER, SE_BIT_NO_REFRACTION,
201
+ } from '../../constants';
202
+
203
+ const swe = new SwissEph();
204
+
205
+ const jd = SwissEph.julianDay(2024, 3, 20, 0);
206
+ const geo = { longitude: 0, latitude: 51.5 };
207
+
208
+ const fmt = (jd: number) => {
209
+ const d = SwissEph.fromJulianDay(jd);
210
+ const h = Math.floor(d.hour);
211
+ const m = Math.floor((d.hour - h) * 60);
212
+ const s = Math.round(((d.hour - h) * 60 - m) * 60);
213
+ return `${h}:${String(m).padStart(2,'0')}:${String(s).padStart(2,'0')} UT`;
214
+ };
215
+
216
+ // Default: upper limb with refraction
217
+ const normal = swe.rise(jd, SE_SUN, geo);
218
+ console.log(`Normal sunrise (upper limb + refraction): ${fmt(normal.jd)}`);
219
+
220
+ // Disc center: when the center of the Sun crosses the horizon
221
+ const center = swe.rise(jd, SE_SUN, geo, { flags: SE_BIT_DISC_CENTER });
222
+ console.log(`Disc center sunrise: ${fmt(center.jd)}`);
223
+
224
+ // No refraction: geometric rise (no atmospheric bending)
225
+ const noRefr = swe.rise(jd, SE_SUN, geo, { flags: SE_BIT_NO_REFRACTION });
226
+ console.log(`No refraction: ${fmt(noRefr.jd)}`);
227
+
228
+ // Both: disc center without refraction
229
+ const both = swe.rise(jd, SE_SUN, geo, {
230
+ flags: SE_BIT_DISC_CENTER | SE_BIT_NO_REFRACTION,
231
+ });
232
+ console.log(`Disc center, no refraction: ${fmt(both.jd)}`);
233
+
234
+ swe.close();
235
+ ```
236
+
237
+ ### Custom atmospheric conditions
238
+
239
+ Atmospheric refraction depends on air pressure and temperature. The defaults are standard conditions (1013.25 mbar, 15 degrees Celsius). You can customize these for your location.
240
+
241
+ ```typescript
242
+ import { SwissEph } from '../index';
243
+ import { SE_SUN } from '../../constants';
244
+
245
+ const swe = new SwissEph();
246
+
247
+ const jd = SwissEph.julianDay(2024, 1, 15, 0);
248
+
249
+ // High altitude location: La Paz, Bolivia (3,640m elevation)
250
+ // Lower pressure and temperature at high altitude
251
+ const laPaz = { longitude: -68.15, latitude: -16.50, altitude: 3640 };
252
+
253
+ const sunriseStandard = swe.rise(jd, SE_SUN, laPaz);
254
+ const sunriseCustom = swe.rise(jd, SE_SUN, laPaz, {
255
+ pressure: 650, // ~650 mbar at 3640m elevation
256
+ temperature: 8, // typical temperature in Celsius
257
+ });
258
+
259
+ const fmt = (jd: number) => {
260
+ const d = SwissEph.fromJulianDay(jd);
261
+ const h = Math.floor(d.hour);
262
+ const m = Math.floor((d.hour - h) * 60);
263
+ const s = Math.round(((d.hour - h) * 60 - m) * 60);
264
+ return `${h}:${String(m).padStart(2,'0')}:${String(s).padStart(2,'0')} UT`;
265
+ };
266
+
267
+ console.log(`La Paz sunrise (standard atm): ${fmt(sunriseStandard.jd)}`);
268
+ console.log(`La Paz sunrise (custom atm): ${fmt(sunriseCustom.jd)}`);
269
+
270
+ swe.close();
271
+ ```
272
+
273
+ ### Finding the next sunrise from any starting time
274
+
275
+ The `rise` function finds the *next* rise after the given Julian Day. If you start from noon and the Sun has already risen, it will find the *following* day's sunrise.
276
+
277
+ ```typescript
278
+ import { SwissEph } from '../index';
279
+ import { SE_SUN } from '../../constants';
280
+
281
+ const swe = new SwissEph();
282
+ const geo = { longitude: -74.006, latitude: 40.713 }; // New York
283
+
284
+ const fmt = (jd: number) => {
285
+ const d = SwissEph.fromJulianDay(jd);
286
+ const h = Math.floor(d.hour);
287
+ const m = Math.floor((d.hour - h) * 60);
288
+ return `${d.year}-${String(d.month).padStart(2,'0')}-${String(d.day).padStart(2,'0')} ${h}:${String(m).padStart(2,'0')} UT`;
289
+ };
290
+
291
+ // Starting from Jan 15 at midnight UT -- finds sunrise on Jan 15
292
+ const jd1 = SwissEph.julianDay(2024, 1, 15, 0);
293
+ console.log(`From midnight: ${fmt(swe.rise(jd1, SE_SUN, geo).jd)}`);
294
+
295
+ // Starting from Jan 15 at noon UT -- sunrise already happened, finds Jan 16
296
+ const jd2 = SwissEph.julianDay(2024, 1, 15, 12);
297
+ console.log(`From noon: ${fmt(swe.rise(jd2, SE_SUN, geo).jd)}`);
298
+
299
+ swe.close();
300
+ ```
301
+
302
+ ### Sunrise and sunset times over a month
303
+
304
+ ```typescript
305
+ import { SwissEph } from '../index';
306
+ import { SE_SUN } from '../../constants';
307
+
308
+ const swe = new SwissEph();
309
+ const tokyo = { longitude: 139.692, latitude: 35.690 };
310
+
311
+ console.log('Sunrise/Sunset in Tokyo, June 2024 (UT):');
312
+
313
+ for (let day = 1; day <= 30; day++) {
314
+ const jd = SwissEph.julianDay(2024, 6, day, 0);
315
+ const rise = swe.rise(jd, SE_SUN, tokyo);
316
+ const set = swe.set(jd, SE_SUN, tokyo);
317
+
318
+ const fmtTime = (jd: number) => {
319
+ const d = SwissEph.fromJulianDay(jd);
320
+ const h = Math.floor(d.hour);
321
+ const m = Math.floor((d.hour - h) * 60);
322
+ return `${h}:${String(m).padStart(2,'0')}`;
323
+ };
324
+
325
+ // Day length in hours
326
+ const dayLength = (set.jd - rise.jd) * 24;
327
+
328
+ console.log(
329
+ ` Jun ${String(day).padStart(2)}:` +
330
+ ` rise ${fmtTime(rise.jd)}` +
331
+ ` set ${fmtTime(set.jd)}` +
332
+ ` (${dayLength.toFixed(1)}h daylight)`
333
+ );
334
+ }
335
+
336
+ swe.close();
337
+ ```
338
+
339
+ ---
340
+
341
+ ## Deep Explanation
342
+
343
+ ### What "rise" means astronomically
344
+
345
+ When we say a celestial body "rises," we mean it crosses the observer's **astronomical horizon** -- the geometric plane tangent to Earth's surface at the observer's location. However, the actual moment of rise is affected by several factors:
346
+
347
+ 1. **Atmospheric refraction**: Earth's atmosphere bends light, making objects appear higher than they geometrically are. At the horizon, this bending is approximately 34 arc-minutes (just over half a degree). This means you can see the Sun even when it is geometrically below the horizon.
348
+
349
+ 2. **Semi-diameter**: The standard definition of sunrise/sunset is when the **upper limb** (top edge) of the Sun's disc appears at the horizon, not the center. The Sun's semi-diameter is about 16 arc-minutes.
350
+
351
+ 3. **Combined effect**: The Sun is considered to have "risen" when its center is about 50 arc-minutes (0.833 degrees) below the geometric horizon: 34' of refraction + 16' of semi-diameter.
352
+
353
+ For the Moon, the semi-diameter varies more (14.5' to 16.7') because the Moon's distance from Earth varies significantly during its orbit.
354
+
355
+ ### Standard altitude for rise/set
356
+
357
+ The Swiss Ephemeris uses these standard altitudes for rise/set (the altitude of the body's center at the moment of rise/set):
358
+
359
+ | Body | Standard altitude | Components |
360
+ |------|------------------|------------|
361
+ | Sun | -0.8333 degrees | -0.5667 deg (refraction) - 0.2666 deg (semi-diameter) |
362
+ | Moon | Varies (~-0.56 to -0.83 deg) | Refraction + actual semi-diameter (depends on distance) |
363
+ | Stars/planets | -0.5667 degrees | Refraction only (point sources have negligible diameter) |
364
+
365
+ ### Atmospheric refraction
366
+
367
+ Refraction depends on atmospheric conditions. At standard conditions (1013.25 mbar pressure, 15 degrees C temperature), the refraction at the horizon is about 34 arc-minutes. The Swiss Ephemeris uses Bennett's formula for refraction.
368
+
369
+ Higher pressure increases refraction (light bends more). Higher temperature decreases it (warmer air is less dense). At high-altitude locations with low pressure, the refraction is notably less.
370
+
371
+ Setting pressure to 0 is equivalent to using `SE_BIT_NO_REFRACTION`.
372
+
373
+ ### The flag constants
374
+
375
+ | Constant | Value | Effect |
376
+ |----------|-------|--------|
377
+ | `SE_BIT_DISC_CENTER` | 256 | Rise/set of the disc center instead of the upper limb. |
378
+ | `SE_BIT_DISC_BOTTOM` | 8192 | Rise/set of the lower limb (bottom edge) of the disc. |
379
+ | `SE_BIT_NO_REFRACTION` | 512 | Ignore atmospheric refraction (geometric rise/set). |
380
+ | `SE_BIT_CIVIL_TWILIGHT` | 1024 | Use -6 degrees altitude instead of standard rise/set. |
381
+ | `SE_BIT_NAUTIC_TWILIGHT` | 2048 | Use -12 degrees altitude. |
382
+ | `SE_BIT_ASTRO_TWILIGHT` | 4096 | Use -18 degrees altitude. |
383
+ | `SE_BIT_FIXED_DISC_SIZE` | 16384 | Use a fixed disc size (ignore actual apparent diameter variation). |
384
+ | `SE_BIT_HINDU_RISING` | combined | Disc center + no refraction + no ecliptic latitude. Used in Indian (Hindu) astronomy where "rising" means the geometric disc center at the horizon. |
385
+
386
+ Flags can be combined with the bitwise OR operator:
387
+ ```typescript
388
+ { flags: SE_BIT_DISC_CENTER | SE_BIT_NO_REFRACTION }
389
+ ```
390
+
391
+ ### Twilight definitions
392
+
393
+ | Twilight type | Sun altitude | Constant | Description |
394
+ |---------------|-------------|----------|-------------|
395
+ | Civil | -6 degrees | `SE_BIT_CIVIL_TWILIGHT` | Bright enough to work outdoors. Brightest stars visible. |
396
+ | Nautical | -12 degrees | `SE_BIT_NAUTIC_TWILIGHT` | Horizon still visible at sea. Many stars visible. |
397
+ | Astronomical | -18 degrees | `SE_BIT_ASTRO_TWILIGHT` | Sky fully dark. Faintest objects observable. |
398
+
399
+ When using a twilight flag with `rise()`, it finds when the Sun rises past that altitude (morning twilight begins). When used with `set()`, it finds when the Sun sets past that altitude (evening twilight ends).
400
+
401
+ ### Dip of the horizon
402
+
403
+ The Swiss Ephemeris does not automatically account for the **dip of the horizon** caused by the observer's elevation. When you are standing on a hill or in a tall building, you can see slightly further below the geometric horizon. The `altitude` field in the `GeoPosition` affects the parallax calculation and slightly adjusts the rise/set altitude to account for this.
404
+
405
+ ### Edge cases
406
+
407
+ - **Polar regions**: At very high latitudes, the Sun (or Moon/planets) may not rise or set on certain days. In the Arctic summer, the Sun stays above the horizon all day (midnight Sun). In the Arctic winter, it stays below all day (polar night). If a rise or set event does not occur, the function may throw an error.
408
+
409
+ - **Circumpolar objects**: Stars that never set (always above the horizon) or never rise (always below) from a given latitude have no rise/set time. The function will throw if asked for a rise/set that cannot occur.
410
+
411
+ - **Starting time matters**: The function finds the *next* event after the given JD. If you start from noon and the Sun has already risen, `rise()` will return the next day's sunrise. To get today's sunrise, start from the previous midnight.
412
+
413
+ - **Moon rise/set gaps**: Because the Moon rises about 50 minutes later each day, there can be days when the Moon does not rise at all (it skipped from rising late one day to early the next). This is normal and most common near the Moon's extremes of declination.
414
+
415
+ ### Options parameter
416
+
417
+ ```typescript
418
+ interface RiseSetOptions {
419
+ pressure?: number; // Atmospheric pressure in mbar (default 1013.25)
420
+ temperature?: number; // Temperature in Celsius (default 15)
421
+ flags?: number; // Bitwise OR of SE_BIT_* constants (default 0)
422
+ }
423
+ ```
424
+
425
+ All options are optional. If you only need to change one setting, the others keep their defaults:
426
+
427
+ ```typescript
428
+ // Only change the flags, keep default pressure and temperature
429
+ swe.rise(jd, SE_SUN, geo, { flags: SE_BIT_DISC_CENTER });
430
+
431
+ // Only change atmospheric conditions, keep default flags
432
+ swe.rise(jd, SE_SUN, geo, { pressure: 900, temperature: 25 });
433
+ ```