practical_astronomy_rust/
datetime.rs

1use crate::macros as pa_m;
2use crate::util as pa_u;
3
4/// Gets the date of Easter for the year specified.
5///
6/// ## Arguments
7///
8/// input_year -- Year for which you'd like the date of Easter.
9///
10/// ## Returns
11///
12/// month, day, year
13pub fn get_date_of_easter(input_year: u32) -> (u32, u32, u32) {
14    let year = input_year as f64;
15
16    let a = year % 19.0;
17    let b = (year / 100.0).floor();
18    let c = year % 100.0;
19    let d = (b / 4.0).floor();
20    let e = b % 4.0;
21    let f = ((b + 8.0) / 25.0).floor();
22    let g = ((b - f + 1.0) / 3.0).floor();
23    let h = ((19.0 * a) + b - d - g + 15.0) % 30.0;
24    let i = (c / 4.0).floor();
25    let k = c % 4.0;
26    let l = (32.0 + 2.0 * (e + i) - h - k) % 7.0;
27    let m = ((a + (11.0 * h) + (22.0 * l)) / 451.0).floor();
28    let n = ((h + l - (7.0 * m) + 114.0) / 31.0).floor();
29    let p = (h + l - (7.0 * m) + 114.0) % 31.0;
30
31    let day = p + 1.0;
32    let month = n;
33
34    return (month as u32, day as u32, year as u32);
35}
36
37/// Calculate day number for a date.
38///
39/// ## Arguments
40///
41/// month, day, year
42///
43/// ## Returns
44///
45/// day_number
46pub fn civil_date_to_day_number(mut month: u32, day: u32, year: u32) -> u32 {
47    if month <= 2 {
48        month = month - 1;
49        month = if pa_u::is_leap_year(year) {
50            month * 62
51        } else {
52            month * 63
53        };
54        month = (month as f64 / 2.0).floor() as u32;
55    } else {
56        month = ((month as f64 + 1.0) * 30.6).floor() as u32;
57        month = if pa_u::is_leap_year(year) {
58            month - 62
59        } else {
60            month - 63
61        };
62    }
63
64    return month + day;
65}
66
67/// Convert a Civil Time (hours,minutes,seconds) to Decimal Hours.
68pub fn civil_time_to_decimal_hours(hours: f64, minutes: f64, seconds: f64) -> f64 {
69    return pa_m::hms_dh(hours, minutes, seconds as f64);
70}
71
72/// Convert Decimal Hours to Civil Time.
73///
74/// ## Returns
75///
76/// hours (u32), minutes (u32), seconds (u32)
77pub fn decimal_hours_to_civil_time(decimal_hours: f64) -> (f64, f64, f64) {
78    let hours = pa_m::dh_hour(decimal_hours);
79    let minutes = pa_m::dh_min(decimal_hours);
80    let seconds = pa_m::dh_sec(decimal_hours);
81
82    return (hours as f64, minutes as f64, seconds as f64);
83}
84
85/// Convert local Civil Time to Universal Time.
86///
87/// ## Returns
88///
89/// UT hours, UT mins, UT secs, GW day, GW month, GW year
90pub fn local_civil_time_to_universal_time(
91    lct_hours: f64,
92    lct_minutes: f64,
93    lct_seconds: f64,
94    is_daylight_savings: bool,
95    zone_correction: i32,
96    local_day: f64,
97    local_month: u32,
98    local_year: u32,
99) -> (u32, u32, u32, u32, u32, u32) {
100    let lct = civil_time_to_decimal_hours(lct_hours, lct_minutes, lct_seconds);
101
102    let daylight_savings_offset = if is_daylight_savings == true { 1 } else { 0 };
103
104    let ut_interim = lct - daylight_savings_offset as f64 - zone_correction as f64;
105    let gday_interim = local_day as f64 + (ut_interim / 24.0);
106
107    let jd = pa_m::cd_jd(gday_interim, local_month, local_year);
108
109    let g_day = pa_m::jdc_day(jd) as f64;
110    let g_month = pa_m::jdc_month(jd);
111    let g_year = pa_m::jdc_year(jd);
112
113    let ut = 24.0 * (g_day - g_day.floor());
114
115    return (
116        pa_m::dh_hour(ut),
117        pa_m::dh_min(ut),
118        pa_m::dh_sec(ut) as u32,
119        g_day.floor() as u32,
120        g_month,
121        g_year,
122    );
123}
124
125/// Convert Universal Time to local Civil Time.
126///
127/// ## Returns
128///
129/// LCT hours, LCT minutes, LCT seconds, day, month, year
130pub fn universal_time_to_local_civil_time(
131    ut_hours: f64,
132    ut_minutes: f64,
133    ut_seconds: f64,
134    is_daylight_savings: bool,
135    zone_correction: i32,
136    gw_day: u32,
137    gw_month: u32,
138    gw_year: u32,
139) -> (u32, u32, u32, u32, u32, u32) {
140    let dst_value = if is_daylight_savings == true { 1 } else { 0 };
141    let ut = pa_m::hms_dh(ut_hours, ut_minutes, ut_seconds);
142    let zone_time = ut + zone_correction as f64;
143    let local_time = zone_time + dst_value as f64;
144    let local_jd_plus_local_time =
145        pa_m::cd_jd(gw_day as f64, gw_month, gw_year) + (local_time / 24.0);
146    let local_day = pa_m::jdc_day(local_jd_plus_local_time) as f64;
147    let integer_day = local_day.floor();
148    let local_month = pa_m::jdc_month(local_jd_plus_local_time);
149    let local_year = pa_m::jdc_year(local_jd_plus_local_time);
150
151    let lct = 24.0 * (local_day - integer_day as f64);
152
153    return (
154        pa_m::dh_hour(lct),
155        pa_m::dh_min(lct),
156        pa_m::dh_sec(lct) as u32,
157        integer_day as u32,
158        local_month,
159        local_year,
160    );
161}
162
163/// Convert Universal Time to Greenwich Sidereal Time.
164///
165/// ## Returns
166/// GST hours, GST minutes, GST seconds
167pub fn universal_time_to_greenwich_sidereal_time(
168    ut_hours: f64,
169    ut_minutes: f64,
170    ut_seconds: f64,
171    gw_day: f64,
172    gw_month: u32,
173    gw_year: u32,
174) -> (u32, u32, f64) {
175    let jd = pa_m::cd_jd(gw_day as f64, gw_month, gw_year);
176    let s = jd - 2451545.0;
177    let t = s / 36525.0;
178    let t01 = 6.697374558 + (2400.051336 * t) + (0.000025862 * t * t);
179    let t02 = t01 - (24.0 * (t01 / 24.0).floor());
180    let ut = pa_m::hms_dh(ut_hours, ut_minutes, ut_seconds);
181    let a = ut * 1.002737909;
182    let gst1 = t02 + a;
183    let gst2 = gst1 - (24.0 * (gst1 / 24.0).floor());
184
185    let gst_hours = pa_m::dh_hour(gst2);
186    let gst_minutes = pa_m::dh_min(gst2);
187    let gst_seconds = pa_m::dh_sec(gst2);
188
189    return (gst_hours, gst_minutes, gst_seconds);
190}
191
192/// Convert Greenwich Sidereal Time to Universal Time.
193///
194/// ## Returns
195/// UT hours, UT minutes, UT seconds, Warning Flag
196pub fn greenwich_sidereal_time_to_universal_time(
197    gst_hours: f64,
198    gst_minutes: f64,
199    gst_seconds: f64,
200    gw_day: f64,
201    gw_month: u32,
202    gw_year: u32,
203) -> (u32, u32, f64, String) {
204    let jd = pa_m::cd_jd(gw_day, gw_month, gw_year);
205    let s = jd - 2451545.0;
206    let t = s / 36525.0;
207    let t01 = 6.697374558 + (2400.051336 * t) + (0.000025862 * t * t);
208    let t02 = t01 - (24.0 * (t01 / 24.0).floor());
209    let gst_hours1 = pa_m::hms_dh(gst_hours, gst_minutes, gst_seconds);
210
211    let a = gst_hours1 - t02;
212    let b = a - (24.0 * (a / 24.0).floor());
213    let ut = b * 0.9972695663;
214    let ut_hours = pa_m::dh_hour(ut);
215    let ut_minutes = pa_m::dh_min(ut);
216    let ut_seconds = pa_m::dh_sec(ut);
217
218    let warning_flag = if ut < 0.065574 { "Warning" } else { "OK" };
219
220    return (ut_hours, ut_minutes, ut_seconds, warning_flag.to_string());
221}
222
223/// Convert Greenwich Sidereal Time to Local Sidereal Time.
224///
225/// ## Returns
226/// LST hours, LST minutes, LST seconds
227pub fn greenwich_sidereal_time_to_local_sidereal_time(
228    gst_hour: f64,
229    gst_minutes: f64,
230    gst_seconds: f64,
231    geographical_longitude: f64,
232) -> (u32, u32, f64) {
233    let gst = pa_m::hms_dh(gst_hour, gst_minutes, gst_seconds);
234    let offset = geographical_longitude / 15.0;
235    let lst_hours1 = gst + offset;
236    let lst_hours2 = lst_hours1 - (24.0 * (lst_hours1 / 24.0).floor());
237
238    let lst_hours = pa_m::dh_hour(lst_hours2);
239    let lst_minutes = pa_m::dh_min(lst_hours2);
240    let lst_seconds = pa_m::dh_sec(lst_hours2);
241
242    return (lst_hours, lst_minutes, lst_seconds);
243}
244
245/// Convert Local Sidereal Time to Greenwich Sidereal Time.
246///
247/// ## Returns
248/// GST hours, GST minutes, GST seconds
249pub fn local_sidereal_time_to_greenwich_sidereal_time(
250    lst_hours: f64,
251    lst_minutes: f64,
252    lst_seconds: f64,
253    geographical_longitude: f64,
254) -> (u32, u32, f64) {
255    let gst = pa_m::hms_dh(lst_hours, lst_minutes, lst_seconds);
256    let long_hours = geographical_longitude / 15.0;
257    let gst1 = gst - long_hours;
258    let gst2 = gst1 - (24.0 * (gst1 / 24.0).floor());
259
260    let gst_hours = pa_m::dh_hour(gst2);
261    let gst_minutes = pa_m::dh_min(gst2);
262    let gst_seconds = pa_m::dh_sec(gst2);
263
264    return (gst_hours, gst_minutes, gst_seconds);
265}