celestial_time/scales/
common.rs1use 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, Err(idx) => {
28 if idx == 0 {
29 return 0.0; }
31 idx - 1 }
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}