use std::fmt::Debug;
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};
use crate::duration::Duration;
use crate::instant::Instant;
const TCB_FACTOR: f64 = 1.550_505e-8;
const TCG_FACTOR: f64 = 6.969_290_134e-10;
pub trait Standard: Debug + Sized + Clone {
fn abbrev() -> &'static str;
fn to_tt(at: Instant) -> Instant;
fn from_tt(at: Instant) -> Instant;
}
pub trait Continuous { }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature ="serde", derive(Serialize, Deserialize))]
pub struct Tt;
impl Standard for Tt {
fn abbrev() -> &'static str {
"TT"
}
fn to_tt(at: Instant) -> Instant {
at
}
fn from_tt(at: Instant) -> Instant {
at
}
}
impl Continuous for Tt { }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature ="serde", derive(Serialize, Deserialize))]
pub struct Tcg;
impl Standard for Tcg {
fn abbrev() -> &'static str {
"TCG"
}
fn to_tt(at: Instant) -> Instant {
Instant(at.0 * (1.0 / (1.0 + TCG_FACTOR)))
}
fn from_tt(at: Instant) -> Instant {
Instant(at.0 * (1.0 + TCG_FACTOR))
}
}
impl Continuous for Tcg { }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature ="serde", derive(Serialize, Deserialize))]
pub struct Tcb;
impl Standard for Tcb {
fn abbrev() -> &'static str {
"TCB"
}
fn to_tt(at: Instant) -> Instant {
Instant(at.0 * (1.0 / (1.0 + TCB_FACTOR)))
}
fn from_tt(at: Instant) -> Instant {
Instant(at.0 * (1.0 + TCB_FACTOR))
}
}
impl Continuous for Tcb { }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature ="serde", derive(Serialize, Deserialize))]
pub struct Tai;
impl Standard for Tai {
fn abbrev() -> &'static str {
"TAI"
}
fn to_tt(at: Instant) -> Instant {
at + Duration::new(32, 184_000_000_000_000_000)
}
fn from_tt(at: Instant) -> Instant {
at - Duration::new(32, 184_000_000_000_000_000)
}
}
impl Continuous for Tai { }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature ="serde", derive(Serialize, Deserialize))]
pub struct Utc;
impl Standard for Utc {
fn abbrev() -> &'static str {
"UTC"
}
fn to_tt(at: Instant) -> Instant {
Tai::to_tt(at)
+ Duration::new(9, 0) + Duration::new(leaps_at(at), 0) }
fn from_tt(at: Instant) -> Instant {
Tai::from_tt(at)
- Duration::new(9, 0) - Duration::new(leaps_at(at), 0) }
}
fn leaps_at(at: Instant) -> i64 {
use crate::epoch::Epoch;
let cmp = at + (Epoch::TimeStandard.as_instant() - Epoch::E1900_0.as_instant());
let secs = cmp.0.seconds_part();
trace!("Comparing seconds {} to leap second list", secs);
#[allow(clippy::unreadable_literal)]
let leaps: Vec<i64> = vec![
2272060800, 2287785600, 2303683200, 2335219200, 2366755200, 2398291200, 2429913600, 2461449600, 2492985600, 2524521600, 2571782400, 2603318400, 2634854400, 2698012800, 2776982400, 2840140800, 2871676800, 2918937600, 2950473600, 2982009600, 3029443200, 3076704000, 3124137600, 3345062400, 3439756800, 3550089600, 3644697600, 3692217600, ];
leaps.iter().enumerate()
.find(|(_n,&leap)| secs <= leap)
.map_or(leaps.len(), |(n,_d)| n) as i64
}
#[cfg(test)]
mod test {
use super::leaps_at;
use crate::date_time::DateTime;
use crate::duration::Duration;
use crate::calendar::Gregorian;
use crate::instant::Instant;
use crate::standard::{Standard, Tai, Tcg, Utc};
#[test]
fn test_to_from_tt() {
crate::setup_logging();
let i = Instant(Duration { secs: 21_309_887, attos: 214_892_349_872_398_743 });
let j = Tai::to_tt(Tai::from_tt(i));
assert_eq!(i, j);
let j = Utc::to_tt(Utc::from_tt(i));
assert_eq!(i, j);
let j = Tcg::to_tt(Tcg::from_tt(i));
assert_eq!(i.0.secs, j.0.secs);
assert!(i.0.attos - j.0.attos < 10400000);
assert!(i.0.attos - j.0.attos > -10400000);
}
#[test]
fn test_leaps_at() {
crate::setup_logging();
let at: Instant = From::from(DateTime::<Gregorian, Utc>::new(1970, 9, 17, 13, 45, 18, 0).unwrap());
assert_eq!(leaps_at(at), 0);
let at: Instant = From::from(DateTime::<Gregorian, Utc>::new(1973, 9, 17, 13, 45, 18, 0).unwrap());
assert_eq!(leaps_at(at), 3);
let at: Instant = From::from(DateTime::<Gregorian, Utc>::new(1973,12, 31, 0, 0, 60, 500_000_000_000_000_000).unwrap());
assert_eq!(leaps_at(at), 3);
let at: Instant = From::from(DateTime::<Gregorian, Utc>::new(1974, 1, 1, 0, 0, 0, 500_000_000_000_000_000).unwrap());
assert_eq!(leaps_at(at), 4);
let at: Instant = From::from(DateTime::<Gregorian, Utc>::new(2019, 9, 17, 13, 45, 18, 0).unwrap());
assert_eq!(leaps_at(at), 28);
}
}