use crate::astro::time::civil;
use crate::astro::time::model::TimeScale;
use crate::astro::time::scales::TimeScales;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct CalendarEpoch {
pub year: i32,
pub month: i32,
pub day: i32,
pub hour: i32,
pub minute: i32,
pub second: f64,
}
impl CalendarEpoch {
pub const fn new(year: i32, month: i32, day: i32, hour: i32, minute: i32, second: f64) -> Self {
Self {
year,
month,
day,
hour,
minute,
second,
}
}
pub(crate) fn time_scales(self, scale: TimeScale) -> TimeScales {
TimeScales::from_scale(
scale,
self.year,
self.month,
self.day,
self.hour,
self.minute,
self.second,
)
.expect("calendar epoch has a finite second")
}
}
pub(crate) fn dt_seconds(t0: &TimeScales, t: &TimeScales) -> f64 {
civil::seconds_between_splits(t.jd_whole, t.tt_fraction, t0.jd_whole, t0.tt_fraction)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn glonasst_resolves_as_utc_plus_three_hours() {
let glo = CalendarEpoch::new(2020, 6, 15, 3, 0, 0.0).time_scales(TimeScale::Glonasst);
let utc = CalendarEpoch::new(2020, 6, 15, 0, 0, 0.0).time_scales(TimeScale::Utc);
assert_eq!(glo, utc);
}
#[test]
fn qzsst_resolves_identically_to_gpst() {
let qzs = CalendarEpoch::new(2020, 6, 15, 12, 0, 0.0).time_scales(TimeScale::Qzsst);
let gps = CalendarEpoch::new(2020, 6, 15, 12, 0, 0.0).time_scales(TimeScale::Gpst);
assert_eq!(qzs, gps);
}
#[test]
fn glonasst_three_hour_shift_crosses_2017_boundary() {
let post = CalendarEpoch::new(2017, 1, 1, 3, 0, 0.0).time_scales(TimeScale::Glonasst);
let post_utc = CalendarEpoch::new(2017, 1, 1, 0, 0, 0.0).time_scales(TimeScale::Utc);
assert_eq!(post, post_utc);
let pre = CalendarEpoch::new(2017, 1, 1, 2, 59, 59.0).time_scales(TimeScale::Glonasst);
let pre_utc = CalendarEpoch::new(2016, 12, 31, 23, 59, 59.0).time_scales(TimeScale::Utc);
assert_eq!(pre, pre_utc);
}
}