use lox_core::f64::consts::SECONDS_PER_DAY;
use lox_core::math::slices::Monotonic;
use crate::deltas::{TimeDelta, ToDelta};
use crate::julian_dates::Epoch::ModifiedJulianDate;
use crate::julian_dates::JulianDate;
use crate::julian_dates::Unit::Days;
use crate::time::Time;
use crate::time_scales::Tai;
use crate::utc::Utc;
const EPOCHS: [u64; 14] = [
36934, 37300, 37512, 37665, 38334, 38395, 38486, 38639, 38761, 38820, 38942, 39004, 39126,
39887,
];
const OFFSETS: [f64; 14] = [
1.417818, 1.422818, 1.372818, 1.845858, 1.945858, 3.240130, 3.340130, 3.440130, 3.540130,
3.640130, 3.740130, 3.840130, 4.313170, 4.213170,
];
const DRIFT_EPOCHS: [u64; 14] = [
37300, 37300, 37300, 37665, 37665, 38761, 38761, 38761, 38761, 38761, 38761, 38761, 39126,
39126,
];
const DRIFT_RATES: [f64; 14] = [
0.0012960, 0.0012960, 0.0012960, 0.0011232, 0.0011232, 0.0012960, 0.0012960, 0.0012960,
0.0012960, 0.0012960, 0.0012960, 0.0012960, 0.0025920, 0.0025920,
];
pub fn delta_utc_tai(utc: &Utc) -> TimeDelta {
debug_assert!(&EPOCHS.is_strictly_increasing());
let mjd = utc.to_delta().days_since_modified_julian_epoch();
if mjd < EPOCHS[0] as f64 {
return TimeDelta::ZERO;
}
let threshold = mjd.floor() as u64;
let position = EPOCHS
.iter()
.rposition(|item| item <= &threshold)
.expect("threshold is >= EPOCHS[0]");
let raw_delta =
OFFSETS[position] + (mjd - DRIFT_EPOCHS[position] as f64) * DRIFT_RATES[position];
let delta = TimeDelta::from_seconds_f64(raw_delta);
-delta
}
pub fn delta_tai_utc(tai: &Time<Tai>) -> TimeDelta {
debug_assert!(&EPOCHS.is_strictly_increasing());
let mjd = tai.julian_date(ModifiedJulianDate, Days);
if mjd < EPOCHS[0] as f64 {
return TimeDelta::ZERO;
}
let threshold = mjd.floor() as u64;
let position = EPOCHS
.iter()
.rposition(|item| item <= &threshold)
.expect("threshold is >= EPOCHS[0]");
let rate_utc = DRIFT_RATES[position] / SECONDS_PER_DAY;
let rate_tai = rate_utc / (1.0 + rate_utc) * SECONDS_PER_DAY;
let offset = OFFSETS[position];
let dt = mjd - DRIFT_EPOCHS[position] as f64 - offset / SECONDS_PER_DAY;
let raw_delta = offset + dt * rate_tai;
TimeDelta::from_seconds_f64(raw_delta)
}