use core::marker::PhantomData;
use uom::si::f64::Time;
use uom::si::time::second;
use crate::sealed::TimeScaleSealed;
pub trait TimeScale: TimeScaleSealed + 'static {
const NAME: &'static str;
}
macro_rules! time_scale_marker {
($name:ident, $human:literal, $doc:literal) => {
#[doc = $doc]
#[derive(Debug, Clone, Copy)]
pub struct $name;
impl TimeScaleSealed for $name {}
impl TimeScale for $name {
const NAME: &'static str = $human;
}
};
}
time_scale_marker!(TAI, "TAI", "International Atomic Time.");
time_scale_marker!(
UTC,
"UTC",
"Coordinated Universal Time (leap-second stepped)."
);
time_scale_marker!(UT1, "UT1", "Universal Time 1 (Earth-rotation based).");
time_scale_marker!(TT, "TT", "Terrestrial Time (TAI + 32.184 s).");
time_scale_marker!(
TDB,
"TDB",
"Barycentric Dynamical Time (relativistic correction to TT)."
);
time_scale_marker!(GPS, "GPS", "GPS Time (TAI − 19 s).");
time_scale_marker!(
GMST,
"GMST",
"Greenwich Mean Sidereal Time (angle, but seconds-ized by convention)."
);
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct SecondsSince<S: TimeScale> {
pub value: Time,
_s: PhantomData<S>,
}
impl<S: TimeScale> SecondsSince<S> {
#[inline]
pub fn new(t: Time) -> Self {
Self {
value: t,
_s: PhantomData,
}
}
#[inline]
pub fn from_seconds(s: f64) -> Self {
Self {
value: Time::new::<second>(s),
_s: PhantomData,
}
}
#[inline]
pub fn as_seconds(self) -> f64 {
self.value.get::<second>()
}
}
#[derive(Debug, Clone, Copy)]
pub struct TimeConverter<From: TimeScale, To: TimeScale> {
offset_seconds: f64,
_f: PhantomData<From>,
_t: PhantomData<To>,
}
impl<From: TimeScale, To: TimeScale> TimeConverter<From, To> {
#[inline]
pub const fn offset_seconds(self) -> f64 {
self.offset_seconds
}
#[inline]
pub fn apply(self, t: SecondsSince<From>) -> SecondsSince<To> {
SecondsSince::from_seconds(t.as_seconds() + self.offset_seconds)
}
#[inline]
pub fn inverse(self) -> TimeConverter<To, From> {
TimeConverter {
offset_seconds: -self.offset_seconds,
_f: PhantomData,
_t: PhantomData,
}
}
}
pub const TAI_TO_TT_OFFSET_S: f64 = 32.184;
pub const GPS_TO_TAI_OFFSET_S: f64 = 19.0;
impl TimeConverter<TAI, TT> {
pub const TAI_TO_TT: Self = Self {
offset_seconds: TAI_TO_TT_OFFSET_S,
_f: PhantomData,
_t: PhantomData,
};
}
impl TimeConverter<TT, TAI> {
pub const TT_TO_TAI: Self = Self {
offset_seconds: -TAI_TO_TT_OFFSET_S,
_f: PhantomData,
_t: PhantomData,
};
}
impl TimeConverter<GPS, TAI> {
pub const GPS_TO_TAI: Self = Self {
offset_seconds: GPS_TO_TAI_OFFSET_S,
_f: PhantomData,
_t: PhantomData,
};
}
impl TimeConverter<TAI, GPS> {
pub const TAI_TO_GPS: Self = Self {
offset_seconds: -GPS_TO_TAI_OFFSET_S,
_f: PhantomData,
_t: PhantomData,
};
}