practical_astronomy_rust/
eclipses.rs

1use crate::macros as pa_m;
2use crate::util as pa_u;
3
4/// Determine if a lunar eclipse is likely to occur.
5///
6/// ## Arguments
7/// * `local_date_day` -- Local date, day part.
8/// * `local_date_month` -- Local date, month part.
9/// * `local_date_year` -- Local date, year part.
10/// * `is_daylight_saving` -- Is daylight savings in effect?
11/// * `zone_correction_hours` -- Time zone correction, in hours.
12///
13/// ## Returns
14/// * `status` -- One of "Lunar eclipse certain", "Lunar eclipse possible", or "No lunar eclipse".
15/// * `event_date_day` -- Date of eclipse event (day).
16/// * `event_date_month` -- Date of eclipse event (month).
17/// * `event_date_year` -- Date of eclipse event (year).
18pub fn lunar_eclipse_occurrence(
19    local_date_day: f64,
20    local_date_month: u32,
21    local_date_year: u32,
22    is_daylight_saving: bool,
23    zone_correction_hours: i32,
24) -> (String, f64, u32, u32) {
25    let daylight_saving = if is_daylight_saving == true { 1 } else { 0 };
26
27    let julian_date_of_full_moon = pa_m::full_moon(
28        daylight_saving,
29        zone_correction_hours,
30        local_date_day,
31        local_date_month,
32        local_date_year,
33    );
34    let g_date_of_full_moon_day = pa_m::jdc_day(julian_date_of_full_moon);
35    let integer_day = (g_date_of_full_moon_day).floor();
36    let g_date_of_full_moon_month = pa_m::jdc_month(julian_date_of_full_moon);
37    let g_date_of_full_moon_year = pa_m::jdc_year(julian_date_of_full_moon);
38    let ut_of_full_moon_hours = g_date_of_full_moon_day - integer_day;
39    let _local_civil_time_hours = pa_m::ut_lct(
40        ut_of_full_moon_hours,
41        0.0,
42        0.0,
43        daylight_saving,
44        zone_correction_hours,
45        integer_day,
46        g_date_of_full_moon_month,
47        g_date_of_full_moon_year,
48    );
49    let local_civil_date_day = pa_m::ut_lc_day(
50        ut_of_full_moon_hours,
51        0.0,
52        0.0,
53        daylight_saving,
54        zone_correction_hours,
55        integer_day,
56        g_date_of_full_moon_month,
57        g_date_of_full_moon_year,
58    );
59    let local_civil_date_month = pa_m::ut_lc_month(
60        ut_of_full_moon_hours,
61        0.0,
62        0.0,
63        daylight_saving,
64        zone_correction_hours,
65        integer_day,
66        g_date_of_full_moon_month,
67        g_date_of_full_moon_year,
68    );
69    let local_civil_date_year = pa_m::ut_lc_year(
70        ut_of_full_moon_hours,
71        0.0,
72        0.0,
73        daylight_saving,
74        zone_correction_hours,
75        integer_day,
76        g_date_of_full_moon_month,
77        g_date_of_full_moon_year,
78    );
79    let eclipse_occurrence = pa_m::lunar_eclipse_occurrence(
80        daylight_saving,
81        zone_correction_hours,
82        local_date_day,
83        local_date_month,
84        local_date_year,
85    );
86
87    let status = eclipse_occurrence;
88    let event_date_day = local_civil_date_day;
89    let event_date_month = local_civil_date_month;
90    let event_date_year = local_civil_date_year;
91
92    return (status, event_date_day, event_date_month, event_date_year);
93}
94
95/// Calculate the circumstances of a lunar eclipse.
96///
97/// ## Arguments
98/// * `local_date_day` -- Local date, day part.
99/// * `local_date_month` -- Local date, month part.
100/// * `local_date_year` -- Local date, year part.
101/// * `is_daylight_saving` -- Is daylight savings in effect?
102/// * `zone_correction_hours` -- Time zone correction, in hours.
103///
104/// ## Returns
105/// * `lunar_eclipse_certain_date_day` -- Lunar eclipse date (day)
106/// * `lunar_eclipse_certain_date_month` -- Lunar eclipse date (month)
107/// * `lunar_eclipse_certain_date_year` -- Lunar eclipse date (year)
108/// * `ut_start_pen_phase_hour` -- Start of penumbral phase (hour)
109/// * `ut_start_pen_phase_minutes` -- Start of penumbral phase (minutes)
110/// * `ut_start_umbral_phase_hour` -- Start of umbral phase (hour)
111/// * `ut_start_umbral_phase_minutes` -- Start of umbral phase (minutes)
112/// * `ut_start_total_phase_hour` -- Start of total phase (hour)
113/// * `ut_start_total_phase_minutes` -- Start of total phase (minutes)
114/// * `ut_mid_eclipse_hour` -- Mid-eclipse (hour)
115/// * `ut_mid_eclipse_minutes` -- Mid-eclipse (minutes)
116/// * `ut_end_total_phase_hour` -- End of total phase (hour)
117/// * `ut_end_total_phase_minutes` -- End of total phase (minutes)
118/// * `ut_end_umbral_phase_hour` -- End of umbral phase (hour)
119/// * `ut_end_umbral_phase_minutes` -- End of umbral phase (minutes)
120/// * `ut_end_pen_phase_hour` -- End of penumbral phase (hour)
121/// * `ut_end_pen_phase_minutes` -- End of penumbral phase (minutes)
122/// * `eclipse_magnitude` -- Eclipse magnitude
123pub fn lunar_eclipse_circumstances(
124    local_date_day: f64,
125    local_date_month: u32,
126    local_date_year: u32,
127    is_daylight_saving: bool,
128    zone_correction_hours: i32,
129) -> (
130    f64,
131    u32,
132    u32,
133    f64,
134    f64,
135    f64,
136    f64,
137    f64,
138    f64,
139    f64,
140    f64,
141    f64,
142    f64,
143    f64,
144    f64,
145    f64,
146    f64,
147    f64,
148) {
149    let daylight_saving = if is_daylight_saving == true { 1 } else { 0 };
150
151    let julian_date_of_full_moon = pa_m::full_moon(
152        daylight_saving,
153        zone_correction_hours,
154        local_date_day,
155        local_date_month,
156        local_date_year,
157    );
158    let g_date_of_full_moon_day = pa_m::jdc_day(julian_date_of_full_moon);
159    let integer_day = g_date_of_full_moon_day.floor();
160    let g_date_of_full_moon_month = pa_m::jdc_month(julian_date_of_full_moon);
161    let g_date_of_full_moon_year = pa_m::jdc_year(julian_date_of_full_moon);
162    let ut_of_full_moon_hours = g_date_of_full_moon_day - integer_day;
163    let _local_civil_time_hours = pa_m::ut_lct(
164        ut_of_full_moon_hours,
165        0.0,
166        0.0,
167        daylight_saving,
168        zone_correction_hours,
169        integer_day,
170        g_date_of_full_moon_month,
171        g_date_of_full_moon_year,
172    );
173    let local_civil_date_day = pa_m::ut_lc_day(
174        ut_of_full_moon_hours,
175        0.0,
176        0.0,
177        daylight_saving,
178        zone_correction_hours,
179        integer_day,
180        g_date_of_full_moon_month,
181        g_date_of_full_moon_year,
182    );
183    let local_civil_date_month = pa_m::ut_lc_month(
184        ut_of_full_moon_hours,
185        0.0,
186        0.0,
187        daylight_saving,
188        zone_correction_hours,
189        integer_day,
190        g_date_of_full_moon_month,
191        g_date_of_full_moon_year,
192    );
193    let local_civil_date_year = pa_m::ut_lc_year(
194        ut_of_full_moon_hours,
195        0.0,
196        0.0,
197        daylight_saving,
198        zone_correction_hours,
199        integer_day,
200        g_date_of_full_moon_month,
201        g_date_of_full_moon_year,
202    );
203    let _eclipse_occurrence = pa_m::lunar_eclipse_occurrence(
204        daylight_saving,
205        zone_correction_hours,
206        local_date_day,
207        local_date_month,
208        local_date_year,
209    );
210    let ut_max_eclipse = pa_m::ut_max_lunar_eclipse(
211        local_date_day,
212        local_date_month,
213        local_date_year,
214        daylight_saving,
215        zone_correction_hours,
216    );
217    let ut_first_contact = pa_m::ut_first_contact_lunar_eclipse(
218        local_date_day,
219        local_date_month,
220        local_date_year,
221        daylight_saving,
222        zone_correction_hours,
223    );
224    let ut_last_contact = pa_m::ut_last_contact_lunar_eclipse(
225        local_date_day,
226        local_date_month,
227        local_date_year,
228        daylight_saving,
229        zone_correction_hours,
230    );
231    let ut_start_umbral_phase = pa_m::ut_start_umbra_lunar_eclipse(
232        local_date_day,
233        local_date_month,
234        local_date_year,
235        daylight_saving,
236        zone_correction_hours,
237    );
238    let ut_end_umbral_phase = pa_m::ut_end_umbra_lunar_eclipse(
239        local_date_day,
240        local_date_month,
241        local_date_year,
242        daylight_saving,
243        zone_correction_hours,
244    );
245    let ut_start_total_phase = pa_m::ut_start_total_lunar_eclipse(
246        local_date_day,
247        local_date_month,
248        local_date_year,
249        daylight_saving,
250        zone_correction_hours,
251    );
252    let ut_end_total_phase = pa_m::ut_end_total_lunar_eclipse(
253        local_date_day,
254        local_date_month,
255        local_date_year,
256        daylight_saving,
257        zone_correction_hours,
258    );
259    let eclipse_magnitude1 = pa_m::mag_lunar_eclipse(
260        local_date_day,
261        local_date_month,
262        local_date_year,
263        daylight_saving,
264        zone_correction_hours,
265    );
266
267    let lunar_eclipse_certain_date_day = local_civil_date_day;
268    let lunar_eclipse_certain_date_month = local_civil_date_month;
269    let lunar_eclipse_certain_date_year = local_civil_date_year;
270    let ut_start_pen_phase_hour = if ut_first_contact == -99.0 {
271        -99.0
272    } else {
273        pa_m::dh_hour(ut_first_contact + 0.008333) as f64
274    };
275    let ut_start_pen_phase_minutes = if ut_first_contact == -99.0 {
276        -99.0
277    } else {
278        pa_m::dh_min(ut_first_contact + 0.008333) as f64
279    };
280    let ut_start_umbral_phase_hour = if ut_start_umbral_phase == -99.0 {
281        -99.0
282    } else {
283        pa_m::dh_hour(ut_start_umbral_phase + 0.008333) as f64
284    };
285    let ut_start_umbral_phase_minutes = if ut_start_umbral_phase == -99.0 {
286        -99.0
287    } else {
288        pa_m::dh_min(ut_start_umbral_phase + 0.008333) as f64
289    };
290    let ut_start_total_phase_hour = if ut_start_total_phase == -99.0 {
291        -99.0
292    } else {
293        pa_m::dh_hour(ut_start_total_phase + 0.008333) as f64
294    };
295    let ut_start_total_phase_minutes = if ut_start_total_phase == -99.0 {
296        -99.0
297    } else {
298        pa_m::dh_min(ut_start_total_phase + 0.008333) as f64
299    };
300    let ut_mid_eclipse_hour = if ut_max_eclipse == -99.0 {
301        -99.0
302    } else {
303        pa_m::dh_hour(ut_max_eclipse + 0.008333) as f64
304    };
305    let ut_mid_eclipse_minutes = if ut_max_eclipse == -99.0 {
306        -99.0
307    } else {
308        pa_m::dh_min(ut_max_eclipse + 0.008333) as f64
309    };
310    let ut_end_total_phase_hour = if ut_end_total_phase == -99.0 {
311        -99.0
312    } else {
313        pa_m::dh_hour(ut_end_total_phase + 0.008333) as f64
314    };
315    let ut_end_total_phase_minutes = if ut_end_total_phase == -99.0 {
316        -99.0
317    } else {
318        pa_m::dh_min(ut_end_total_phase + 0.008333) as f64
319    };
320    let ut_end_umbral_phase_hour = if ut_end_umbral_phase == -99.0 {
321        -99.0
322    } else {
323        pa_m::dh_hour(ut_end_umbral_phase + 0.008333) as f64
324    };
325    let ut_end_umbral_phase_minutes = if ut_end_umbral_phase == -99.0 {
326        -99.0
327    } else {
328        pa_m::dh_min(ut_end_umbral_phase + 0.008333) as f64
329    };
330    let ut_end_pen_phase_hour = if ut_last_contact == -99.0 {
331        -99.0
332    } else {
333        pa_m::dh_hour(ut_last_contact + 0.008333) as f64
334    };
335    let ut_end_pen_phase_minutes = if ut_last_contact == -99.0 {
336        -99.0
337    } else {
338        pa_m::dh_min(ut_last_contact + 0.008333) as f64
339    };
340    let eclipse_magnitude = if eclipse_magnitude1 == -99.0 {
341        -99.0
342    } else {
343        pa_u::round_f64(eclipse_magnitude1, 2)
344    };
345
346    return (
347        lunar_eclipse_certain_date_day,
348        lunar_eclipse_certain_date_month,
349        lunar_eclipse_certain_date_year,
350        ut_start_pen_phase_hour,
351        ut_start_pen_phase_minutes,
352        ut_start_umbral_phase_hour,
353        ut_start_umbral_phase_minutes,
354        ut_start_total_phase_hour,
355        ut_start_total_phase_minutes,
356        ut_mid_eclipse_hour,
357        ut_mid_eclipse_minutes,
358        ut_end_total_phase_hour,
359        ut_end_total_phase_minutes,
360        ut_end_umbral_phase_hour,
361        ut_end_umbral_phase_minutes,
362        ut_end_pen_phase_hour,
363        ut_end_pen_phase_minutes,
364        eclipse_magnitude,
365    );
366}
367
368/// Determine if a solar eclipse is likely to occur.
369///
370/// ## Arguments
371/// * `local_date_day` -- Local date, day part.
372/// * `local_date_month` -- Local date, month part.
373/// * `local_date_year` -- Local date, year part.
374/// * `is_daylight_saving` -- Is daylight savings in effect?
375/// * `zone_correction_hours` -- Time zone correction, in hours.
376///
377/// ## Returns
378/// * `status` -- One of "Solar eclipse certain", "Solar eclipse possible", or "No solar eclipse".
379/// * `event_date_day` -- Date of eclipse event (day).
380/// * `event_date_month` -- Date of eclipse event (month).
381/// * `event_date_year` -- Date of eclipse event (year).
382pub fn solar_eclipse_occurrence(
383    local_date_day: f64,
384    local_date_month: u32,
385    local_date_year: u32,
386    is_daylight_saving: bool,
387    zone_correction_hours: i32,
388) -> (String, f64, u32, u32) {
389    let daylight_saving = if is_daylight_saving == true { 1 } else { 0 };
390
391    let julian_date_of_new_moon = pa_m::new_moon(
392        daylight_saving,
393        zone_correction_hours,
394        local_date_day,
395        local_date_month,
396        local_date_year,
397    );
398    let g_date_of_new_moon_day = pa_m::jdc_day(julian_date_of_new_moon);
399    let integer_day = (g_date_of_new_moon_day).floor();
400    let g_date_of_new_moon_month = pa_m::jdc_month(julian_date_of_new_moon);
401    let g_date_of_new_moon_year = pa_m::jdc_year(julian_date_of_new_moon);
402    let ut_of_new_moon_hours = g_date_of_new_moon_day - integer_day;
403    let _local_civil_time_hours = pa_m::ut_lct(
404        ut_of_new_moon_hours,
405        0.0,
406        0.0,
407        daylight_saving,
408        zone_correction_hours,
409        integer_day,
410        g_date_of_new_moon_month,
411        g_date_of_new_moon_year,
412    );
413    let local_civil_date_day = pa_m::ut_lc_day(
414        ut_of_new_moon_hours,
415        0.0,
416        0.0,
417        daylight_saving,
418        zone_correction_hours,
419        integer_day,
420        g_date_of_new_moon_month,
421        g_date_of_new_moon_year,
422    );
423    let local_civil_date_month = pa_m::ut_lc_month(
424        ut_of_new_moon_hours,
425        0.0,
426        0.0,
427        daylight_saving,
428        zone_correction_hours,
429        integer_day,
430        g_date_of_new_moon_month,
431        g_date_of_new_moon_year,
432    );
433    let local_civil_date_year = pa_m::ut_lc_year(
434        ut_of_new_moon_hours,
435        0.0,
436        0.0,
437        daylight_saving,
438        zone_correction_hours,
439        integer_day,
440        g_date_of_new_moon_month,
441        g_date_of_new_moon_year,
442    );
443    let eclipse_occurrence = pa_m::solar_eclipse_occurrence(
444        daylight_saving,
445        zone_correction_hours,
446        local_date_day,
447        local_date_month,
448        local_date_year,
449    );
450
451    let status = eclipse_occurrence;
452    let event_date_day = local_civil_date_day;
453    let event_date_month = local_civil_date_month;
454    let event_date_year = local_civil_date_year;
455
456    return (status, event_date_day, event_date_month, event_date_year);
457}
458
459/// Calculate the circumstances of a lunar eclipse.
460///
461/// ## Arguments
462/// * `local_date_day` -- Local date, day part.
463/// * `local_date_month` -- Local date, month part.
464/// * `local_date_year` -- Local date, year part.
465/// * `is_daylight_saving` -- Is daylight savings in effect?
466/// * `zone_correction_hours` -- Time zone correction, in hours.
467/// * `geog_longitude_deg` -- Geographical longitude of observer.
468/// * `geog_latitude_deg` -- Geographical latitude of observer.
469///
470/// ## Returns
471/// * `solar_eclipse_certain_date_day` -- Solar eclipse date (day)
472/// * `solar_eclipse_certain_date_month` -- Solar eclipse date (month)
473/// * `solar_eclipse_certain_date_year` -- Solar eclipse date (year)
474/// * `ut_first_contact_hour` -- First contact of shadow (hour)
475/// * `ut_first_contact_minutes` -- First contact of shadow (minutes)
476/// * `ut_mid_eclipse_hour` -- Mid-eclipse (hour)
477/// * `ut_mid_eclipse_minutes` -- Mid-eclipse (minutes)
478/// * `ut_last_contact_hour` -- Last contact of shadow (hour)
479/// * `ut_last_contact_minutes` -- Last contact of shadow (minutes)
480/// * `eclipse_magnitude` -- Eclipse magnitude
481pub fn solar_eclipse_circumstances(
482    local_date_day: f64,
483    local_date_month: u32,
484    local_date_year: u32,
485    is_daylight_saving: bool,
486    zone_correction_hours: i32,
487    geog_longitude_deg: f64,
488    geog_latitude_deg: f64,
489) -> (f64, u32, u32, f64, f64, f64, f64, f64, f64, f64) {
490    let daylight_saving = if is_daylight_saving == true { 1 } else { 0 };
491
492    let julian_date_of_new_moon = pa_m::new_moon(
493        daylight_saving,
494        zone_correction_hours,
495        local_date_day,
496        local_date_month,
497        local_date_year,
498    );
499    let g_date_of_new_moon_day = pa_m::jdc_day(julian_date_of_new_moon);
500    let integer_day = (g_date_of_new_moon_day).floor();
501    let g_date_of_new_moon_month = pa_m::jdc_month(julian_date_of_new_moon);
502    let g_date_of_new_moon_year = pa_m::jdc_year(julian_date_of_new_moon);
503    let ut_of_new_moon_hours = g_date_of_new_moon_day - integer_day;
504    let _local_civil_time_hours = pa_m::ut_lct(
505        ut_of_new_moon_hours,
506        0.0,
507        0.0,
508        daylight_saving,
509        zone_correction_hours,
510        integer_day,
511        g_date_of_new_moon_month,
512        g_date_of_new_moon_year,
513    );
514    let local_civil_date_day = pa_m::ut_lc_day(
515        ut_of_new_moon_hours,
516        0.0,
517        0.0,
518        daylight_saving,
519        zone_correction_hours,
520        integer_day,
521        g_date_of_new_moon_month,
522        g_date_of_new_moon_year,
523    );
524    let local_civil_date_month = pa_m::ut_lc_month(
525        ut_of_new_moon_hours,
526        0.0,
527        0.0,
528        daylight_saving,
529        zone_correction_hours,
530        integer_day,
531        g_date_of_new_moon_month,
532        g_date_of_new_moon_year,
533    );
534    let local_civil_date_year = pa_m::ut_lc_year(
535        ut_of_new_moon_hours,
536        0.0,
537        0.0,
538        daylight_saving,
539        zone_correction_hours,
540        integer_day,
541        g_date_of_new_moon_month,
542        g_date_of_new_moon_year,
543    );
544    let _eclipse_occurrence = pa_m::solar_eclipse_occurrence(
545        daylight_saving,
546        zone_correction_hours,
547        local_date_day,
548        local_date_month,
549        local_date_year,
550    );
551    let ut_max_eclipse = pa_m::ut_max_solar_eclipse(
552        local_date_day,
553        local_date_month,
554        local_date_year,
555        daylight_saving,
556        zone_correction_hours,
557        geog_longitude_deg,
558        geog_latitude_deg,
559    );
560    let ut_first_contact = pa_m::ut_first_contact_solar_eclipse(
561        local_date_day,
562        local_date_month,
563        local_date_year,
564        daylight_saving,
565        zone_correction_hours,
566        geog_longitude_deg,
567        geog_latitude_deg,
568    );
569    let ut_last_contact = pa_m::ut_last_contact_solar_eclipse(
570        local_date_day,
571        local_date_month,
572        local_date_year,
573        daylight_saving,
574        zone_correction_hours,
575        geog_longitude_deg,
576        geog_latitude_deg,
577    );
578    let magnitude = pa_m::mag_solar_eclipse(
579        local_date_day,
580        local_date_month,
581        local_date_year,
582        daylight_saving,
583        zone_correction_hours,
584        geog_longitude_deg,
585        geog_latitude_deg,
586    );
587
588    let solar_eclipse_certain_date_day = local_civil_date_day;
589    let solar_eclipse_certain_date_month = local_civil_date_month;
590    let solar_eclipse_certain_date_year = local_civil_date_year;
591    let ut_first_contact_hour = if ut_first_contact == -99.0 {
592        -99.0
593    } else {
594        pa_m::dh_hour(ut_first_contact + 0.008333) as f64
595    };
596    let ut_first_contact_minutes = if ut_first_contact == -99.0 {
597        -99.0
598    } else {
599        pa_m::dh_min(ut_first_contact + 0.008333) as f64
600    };
601    let ut_mid_eclipse_hour = if ut_max_eclipse == -99.0 {
602        -99.0
603    } else {
604        pa_m::dh_hour(ut_max_eclipse + 0.008333) as f64
605    };
606    let ut_mid_eclipse_minutes = if ut_max_eclipse == -99.0 {
607        -99.0
608    } else {
609        pa_m::dh_min(ut_max_eclipse + 0.008333) as f64
610    };
611    let ut_last_contact_hour = if ut_last_contact == -99.0 {
612        -99.0
613    } else {
614        pa_m::dh_hour(ut_last_contact + 0.008333) as f64
615    };
616    let ut_last_contact_minutes = if ut_last_contact == -99.0 {
617        -99.0
618    } else {
619        pa_m::dh_min(ut_last_contact + 0.008333) as f64
620    };
621    let eclipse_magnitude = if magnitude == -99.0 {
622        -99.0
623    } else {
624        pa_u::round_f64(magnitude, 3)
625    };
626
627    return (
628        solar_eclipse_certain_date_day,
629        solar_eclipse_certain_date_month,
630        solar_eclipse_certain_date_year,
631        ut_first_contact_hour,
632        ut_first_contact_minutes,
633        ut_mid_eclipse_hour,
634        ut_mid_eclipse_minutes,
635        ut_last_contact_hour,
636        ut_last_contact_minutes,
637        eclipse_magnitude,
638    );
639}