use crate::{
Date, Duration, Month, TimePoint, Years,
time_scale::{AbsoluteTimeScale, TerrestrialTime, TimeScale, datetime::UniformDateTimeScale},
units::{Second, SecondsPerYear},
};
pub type TaiTime<Representation = i64, Period = Second> = TimePoint<Tai, Representation, Period>;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Tai;
impl TimeScale for Tai {
const NAME: &'static str = "International Atomic Time";
const ABBREVIATION: &'static str = "TAI";
}
impl AbsoluteTimeScale for Tai {
const EPOCH: Date<i32> = match Date::from_historic_date(1958, Month::January, 1) {
Ok(epoch) => epoch,
Err(_) => unreachable!(),
};
}
impl UniformDateTimeScale for Tai {}
impl TerrestrialTime for Tai {
type Representation = u8;
type Period = SecondsPerYear;
const TAI_OFFSET: Duration<Self::Representation, Self::Period> = Years::new(0);
}
#[cfg(test)]
fn check_gregorian_datetime(
year: i32,
month: Month,
day: u8,
hour: u8,
minute: u8,
second: u8,
time_since_epoch: crate::duration::Seconds<i64>,
) {
assert_eq!(
TaiTime::from_gregorian_datetime(year, month, day, hour, minute, second)
.unwrap()
.time_since_epoch(),
time_since_epoch
);
}
#[test]
fn known_timestamps() {
use crate::Month::*;
use crate::duration::Seconds;
check_gregorian_datetime(1958, January, 1, 0, 0, 0, Seconds::new(0));
check_gregorian_datetime(1958, January, 2, 0, 0, 0, Seconds::new(86400));
check_gregorian_datetime(1960, January, 1, 0, 0, 0, Seconds::new(63072000));
check_gregorian_datetime(1961, January, 1, 0, 0, 0, Seconds::new(94694400));
check_gregorian_datetime(1970, January, 1, 0, 0, 0, Seconds::new(378691200));
check_gregorian_datetime(1976, January, 1, 0, 0, 0, Seconds::new(567993600));
check_gregorian_datetime(2025, July, 16, 16, 23, 24, Seconds::new(2131374204));
check_gregorian_datetime(2034, December, 26, 8, 2, 37, Seconds::new(2429424157));
check_gregorian_datetime(2760, April, 1, 21, 59, 58, Seconds::new(25316575198));
check_gregorian_datetime(1643, January, 4, 1, 1, 33, Seconds::new(-9940143507));
}
#[cfg(test)]
fn gregorian_datetime_roundtrip(
year: i32,
month: Month,
day: u8,
hour: u8,
minute: u8,
second: u8,
) {
use crate::GregorianDate;
use crate::IntoDateTime;
let time =
TaiTime::<i64, _>::from_gregorian_datetime(year, month, day, hour, minute, second).unwrap();
let (date, hour2, minute2, second2) = time.into_datetime();
let gregorian_date = GregorianDate::from_date(date);
assert_eq!(gregorian_date.year(), year);
assert_eq!(gregorian_date.month(), month);
assert_eq!(gregorian_date.day(), day);
assert_eq!(hour, hour2);
assert_eq!(minute, minute2);
assert_eq!(second, second2);
}
#[test]
fn date_decomposition() {
gregorian_datetime_roundtrip(1999, Month::August, 22, 0, 0, 0);
gregorian_datetime_roundtrip(1958, Month::January, 1, 0, 0, 0);
gregorian_datetime_roundtrip(1958, Month::January, 2, 0, 0, 0);
gregorian_datetime_roundtrip(1960, Month::January, 1, 0, 0, 0);
gregorian_datetime_roundtrip(1961, Month::January, 1, 0, 0, 0);
gregorian_datetime_roundtrip(1970, Month::January, 1, 0, 0, 0);
gregorian_datetime_roundtrip(1976, Month::January, 1, 0, 0, 0);
gregorian_datetime_roundtrip(2025, Month::July, 16, 16, 23, 24);
gregorian_datetime_roundtrip(2034, Month::December, 26, 8, 2, 37);
gregorian_datetime_roundtrip(2760, Month::April, 1, 21, 59, 58);
gregorian_datetime_roundtrip(1643, Month::January, 4, 1, 1, 33);
gregorian_datetime_roundtrip(1996, Month::January, 1, 3, 0, 0);
}