Skip to main content

celestial_time/scales/
common.rs

1use crate::{TimeError, TimeResult};
2
3pub fn get_tai_utc_offset(year: i32, month: i32, day: i32, fraction: f64) -> f64 {
4    use crate::constants::{PRE_LEAP_SECOND_ENTRIES, TAI_UTC_OFFSETS, UTC_DRIFT_CORRECTIONS};
5
6    if !(0.0..=1.0).contains(&fraction) {
7        return 0.0;
8    }
9
10    let my = (month - 14) / 12;
11    let iypmy = year + my;
12    let modified_jd = ((1461 * (iypmy + 4800)) / 4 + (367 * (month - 2 - 12 * my)) / 12
13        - (3 * ((iypmy + 4900) / 100)) / 4
14        + day
15        - 2432076) as f64;
16
17    if year < TAI_UTC_OFFSETS[0].0 {
18        return 0.0;
19    }
20
21    let m = 12 * year + month;
22
23    let i = match TAI_UTC_OFFSETS
24        .binary_search_by(|&(entry_year, entry_month, _)| (12 * entry_year + entry_month).cmp(&m))
25    {
26        Ok(idx) => idx, // Exact match found
27        Err(idx) => {
28            if idx == 0 {
29                return 0.0; // Before the first entry
30            }
31            idx - 1 // Use the entry just before the insertion point
32        }
33    };
34
35    let mut tai_minus_utc = TAI_UTC_OFFSETS[i].2;
36
37    if i < PRE_LEAP_SECOND_ENTRIES {
38        let (drift_mjd, drift_rate) = UTC_DRIFT_CORRECTIONS[i];
39        tai_minus_utc += (modified_jd + fraction - drift_mjd) * drift_rate;
40    }
41
42    tai_minus_utc
43}
44
45pub fn next_calendar_day(year: i32, month: i32, day: i32) -> TimeResult<(i32, i32, i32)> {
46    let days_in_month = match month {
47        1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
48        4 | 6 | 9 | 11 => 30,
49        2 => {
50            if is_leap_year(year) {
51                29
52            } else {
53                28
54            }
55        }
56        _ => {
57            return Err(TimeError::ConversionError(format!(
58                "Invalid month: {}",
59                month
60            )))
61        }
62    };
63
64    if day < days_in_month {
65        Ok((year, month, day + 1))
66    } else if month < 12 {
67        Ok((year, month + 1, 1))
68    } else {
69        Ok((year + 1, 1, 1))
70    }
71}
72
73pub fn is_leap_year(year: i32) -> bool {
74    (year % 4 == 0) && (year % 100 != 0 || year % 400 == 0)
75}