use e_utils::chrono::{DateTime, TimeZone, Utc};
use std::fmt;
pub static EPOCH_DELTA: i64 = 2208988800i64;
static NTP_SCALE: f64 = 4294967295.0_f64;
#[derive(Debug, PartialEq, Default, Copy, Clone)]
pub struct ShortFormat {
pub sec: u16,
pub frac: u16,
}
#[derive(Debug, PartialEq, Default, Copy, Clone)]
pub struct TimestampFormat {
pub sec: u32,
pub frac: u32,
}
impl TimestampFormat {
pub fn now() -> Self {
let now = e_utils::chrono::Utc::now();
let sec = now.timestamp() + EPOCH_DELTA; let frac = (now.timestamp_subsec_nanos() as f64 * NTP_SCALE / 1e9) as u32;
TimestampFormat {
sec: sec as u32,
frac,
}
}
}
impl From<ShortFormat> for DateTime<Utc> {
fn from(t: ShortFormat) -> Self {
let total_secs = t.sec as i64 - EPOCH_DELTA;
let nanos = (t.frac as f64 / NTP_SCALE * 1e9) as u32;
Utc.timestamp_opt(total_secs, nanos).unwrap()
}
}
impl From<DateTime<Utc>> for ShortFormat {
fn from(dt: DateTime<Utc>) -> Self {
let sec = (dt.timestamp() + EPOCH_DELTA) as u16;
let frac = (dt.timestamp_subsec_nanos() as f64 * NTP_SCALE / 1e9) as u16;
ShortFormat { sec, frac }
}
}
impl fmt::Display for ShortFormat {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let dt: DateTime<Utc> = (*self).into();
write!(f, "{}", dt.format("%a %b %e %T %Y")) }
}
impl From<ShortFormat> for u32 {
fn from(t: ShortFormat) -> u32 {
(t.sec as u32) << 16 | t.frac as u32
}
}
impl From<u32> for ShortFormat {
fn from(t: u32) -> ShortFormat {
ShortFormat {
sec: (t >> 16) as u16,
frac: t as u16,
}
}
}
impl From<TimestampFormat> for DateTime<Utc> {
fn from(t: TimestampFormat) -> Self {
let total_secs = t.sec as i64 - EPOCH_DELTA;
let nanos = (t.frac as f64 / NTP_SCALE * 1e9) as u32;
Utc.timestamp_opt(total_secs, nanos).unwrap()
}
}
impl From<DateTime<Utc>> for TimestampFormat {
fn from(dt: DateTime<Utc>) -> Self {
let sec = (dt.timestamp() + EPOCH_DELTA) as u32;
let frac = (dt.timestamp_subsec_nanos() as f64 * NTP_SCALE / 1e9) as u32;
TimestampFormat { sec, frac }
}
}
impl fmt::Display for TimestampFormat {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let dt: DateTime<Utc> = (*self).into();
write!(f, "{}", dt.format("%a %b %e %T %Y"))
}
}
impl From<TimestampFormat> for u64 {
fn from(t: TimestampFormat) -> u64 {
(t.sec as u64) << 32 | t.frac as u64
}
}
impl From<u64> for TimestampFormat {
fn from(t: u64) -> TimestampFormat {
TimestampFormat {
sec: (t >> 32) as u32,
frac: t as u32,
}
}
}
#[test]
fn timestamp_conversions() {
let chrono_now = Utc::now();
let short_format: ShortFormat = chrono_now.into();
let converted_back: DateTime<Utc> = short_format.into();
assert!(
(chrono_now - converted_back)
.num_nanoseconds()
.unwrap()
.abs()
< 1000
);
let ts_format: TimestampFormat = chrono_now.into();
let converted_back: DateTime<Utc> = ts_format.into();
assert!(
(chrono_now - converted_back)
.num_nanoseconds()
.unwrap()
.abs()
< 1000
);
}