1use std::ops::Sub;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
4pub struct NtpTimestamp {
5 inner: time::Duration,
7}
8
9impl NtpTimestamp {
10 pub const ZERO: Self = Self {
11 inner: time::Duration::ZERO,
12 };
13
14 pub fn now() -> Self {
15 let epoch = time::Date::from_calendar_date(1900, time::Month::January, 1).unwrap();
16 let epoch = time::OffsetDateTime::new_utc(epoch, time::Time::MIDNIGHT);
17
18 Self {
19 inner: time::OffsetDateTime::now_utc() - epoch,
20 }
21 }
22
23 pub fn as_seconds_f64(self) -> f64 {
24 self.inner.as_seconds_f64()
25 }
26
27 pub fn to_fixed_u64(self) -> u64 {
28 let seconds = self.inner.whole_seconds() as u64;
29 let subseconds =
30 (self.inner.subsec_nanoseconds() as f64 / 1_000_000_000.) * u32::MAX as f64;
31 let subseconds = subseconds as u64;
32
33 (seconds << 32) | subseconds
34 }
35
36 pub fn to_fixed_u32(self) -> u32 {
37 ((self.to_fixed_u64() >> 16) & u64::from(u32::MAX)) as u32
38 }
39
40 pub fn from_fixed_u64(fixed: u64) -> Self {
41 let seconds = (fixed >> 32) as i64;
42
43 let subseconds = (fixed & u64::from(u32::MAX)) as u32;
44 let subseconds = subseconds as f64 / (u32::MAX as f64);
45
46 Self {
47 inner: time::Duration::new(seconds, (subseconds * 1_000_000_000.) as i32),
48 }
49 }
50
51 pub fn from_fixed_u32(fixed: u32) -> Self {
52 let seconds = (fixed >> 16) as i64;
53
54 let subseconds = (fixed & u32::from(u16::MAX)) as u16;
55 let subseconds = subseconds as f64 / (u16::MAX as f64);
56
57 Self {
58 inner: time::Duration::new(seconds, (subseconds * 1_000_000_000.) as i32),
59 }
60 }
61}
62
63impl Sub for NtpTimestamp {
64 type Output = time::Duration;
65
66 fn sub(self, rhs: Self) -> Self::Output {
67 self.inner - rhs.inner
68 }
69}