use crate::{Duration, Epoch, Instant};
#[allow(clippy::unreadable_literal)]
const IANA_NTP_LEAP_SECONDS: &[i64] = &[
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, ];
pub fn leap_instants() -> impl Iterator<Item = Instant> {
LeapInstantIter { i: 0 }
}
pub struct LeapInstantIter {
i: usize,
}
impl Iterator for LeapInstantIter {
type Item = Instant;
#[allow(clippy::cast_possible_wrap)] fn next(&mut self) -> Option<Self::Item> {
if self.i >= IANA_NTP_LEAP_SECONDS.len() {
None
} else {
let leaps_elapsed = self.i + 1;
let offset = Duration::new(IANA_NTP_LEAP_SECONDS[self.i] + leaps_elapsed as i64, 0);
self.i += 1;
Some(Epoch::Ntp.as_instant() + offset)
}
}
}
#[must_use]
pub fn leap_seconds_elapsed_at(i: Instant) -> i64 {
let mut count: i64 = 0;
for leap_instant in leap_instants() {
if i >= leap_instant {
count += 1;
} else {
break;
}
}
count
}
#[cfg(test)]
mod test {
use super::{leap_instants, leap_seconds_elapsed_at};
use crate::{DateTime, Epoch, Gregorian, Instant, Utc};
#[test]
fn test_leap_instants() {
let fourth = leap_instants().skip(3).next().unwrap();
let dur = fourth - Epoch::Ntp.as_instant();
assert_eq!(dur.secs, 2335219200 + 4);
}
#[test]
fn test_leap_seconds_elapsed_at() {
let at: Instant =
From::from(DateTime::<Gregorian, Utc>::new(1970, 9, 17, 13, 45, 18, 0).unwrap());
assert_eq!(leap_seconds_elapsed_at(at), 0);
let at: Instant =
From::from(DateTime::<Gregorian, Utc>::new(1973, 9, 17, 13, 45, 18, 0).unwrap());
assert_eq!(leap_seconds_elapsed_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!(leap_seconds_elapsed_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!(leap_seconds_elapsed_at(at), 4);
let at: Instant =
From::from(DateTime::<Gregorian, Utc>::new(2019, 9, 17, 13, 45, 18, 0).unwrap());
assert_eq!(leap_seconds_elapsed_at(at), 28);
}
}