use crate::{
ATTOS_PER_SEC_I128, Dt, J2000_JD_TT, MARS_MSD_REF_JD_INT, MARS_MSD_REF_TOD_SEC,
MARS_MSD_REF_TOD_SUBSEC, MARS_REF_TT, MARS_SOL_ATTOS, MARS_SOL_LENGTH_SEC, Real,
SEC_PER_DAYI64, SEC_PER_DAYI128, Scale, TSpan, floor_f, to_sec_f,
};
impl Dt {
pub(crate) const fn elapsed_to_attos_since_mars_ref(numerical_tt: TSpan) -> i128 {
let days_since_j2000 = numerical_tt.sec.div_euclid(SEC_PER_DAYI64);
let tod_sec = numerical_tt.sec.rem_euclid(SEC_PER_DAYI64);
let jd_days = J2000_JD_TT + days_since_j2000;
let days_diff = jd_days - MARS_MSD_REF_JD_INT;
let mut sec_diff = (days_diff as i128) * SEC_PER_DAYI128
+ (tod_sec as i128 - MARS_MSD_REF_TOD_SEC as i128);
let mut attos_diff = (numerical_tt.attos as i128) - (MARS_MSD_REF_TOD_SUBSEC as i128);
if attos_diff < 0 {
attos_diff += ATTOS_PER_SEC_I128;
sec_diff -= 1;
}
sec_diff * ATTOS_PER_SEC_I128 + attos_diff
}
pub const fn to_msd_exact(self) -> (i64, u128) {
let tt = self.to(Scale::TT);
let elapsed = Self::elapsed_to_attos_since_mars_ref(tt);
let attos_per_sol = MARS_SOL_ATTOS;
let whole_sols = elapsed.div_euclid(attos_per_sol) as i64;
let frac_attos = elapsed.rem_euclid(attos_per_sol) as u128;
(whole_sols, frac_attos)
}
#[inline]
pub const fn to_mtc(self) -> TSpan {
let (_, frac_attos) = self.to_msd_exact();
TSpan::from_attos(frac_attos as i128)
}
pub const fn from_msd_exact(whole_sols: i64, frac_attos: u128) -> Self {
let elapsed_attos = (whole_sols as i128) * MARS_SOL_ATTOS + frac_attos as i128;
let tt = MARS_REF_TT.add(TSpan::from_attos(elapsed_attos));
Self::from(tt.sec, tt.attos, Scale::TT)
}
pub const fn from_msd(msd: Real) -> Self {
let whole = floor_f(msd) as i64;
let frac = msd - f!(whole);
let frac_span = TSpan::from_sec_f(frac * MARS_SOL_LENGTH_SEC);
Self::from_msd_exact(whole, frac_span.to_attos() as u128)
}
#[inline]
pub const fn to_msd(self) -> Real {
let (whole, frac) = self.to_msd_exact();
f!(whole) + to_sec_f(frac) / MARS_SOL_LENGTH_SEC
}
}