1use std::ops::Add;
2use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
3
4#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5pub struct SystemInstant {
6 instant: Instant,
7 duration_since_unix_epoch: Duration,
8}
9
10impl SystemInstant {
11 pub fn now() -> Self {
12 Self {
13 instant: Instant::now(),
14 duration_since_unix_epoch: SystemTime::now()
15 .duration_since(UNIX_EPOCH)
16 .unwrap_or_else(|_| Duration::from_secs(0)),
17 }
18 }
19
20 pub fn instant(&self, duration_since_unix_epoch: Duration) -> Instant {
21 self.instant + duration_since_unix_epoch - self.duration_since_unix_epoch
22 }
23
24 pub fn duration_since_unix_epoch(&self) -> Duration {
25 self.duration_since_unix_epoch
26 }
27
28 pub fn unix(&self, now: Instant) -> Duration {
29 now.duration_since(self.instant)
30 .add(self.duration_since_unix_epoch)
31 }
32
33 pub fn ntp(&self, now: Instant) -> u64 {
34 SystemInstant::unix2ntp(self.unix(now))
35 }
36
37 pub fn unix2ntp(duration_since_unix_epoch: Duration) -> u64 {
38 let u = duration_since_unix_epoch.as_nanos() as u64;
39
40 let mut s = u / 1_000_000_000;
41 s += 0x83AA7E80; let mut f = u % 1_000_000_000;
43 f <<= 32;
44 f /= 1_000_000_000;
45 s <<= 32;
46
47 s | f
48 }
49
50 pub fn ntp2unix(ntp: u64) -> Duration {
51 let mut s = ntp >> 32;
52 let mut f = ntp & 0xFFFFFFFF;
53 f *= 1_000_000_000;
54 f >>= 32;
55 s -= 0x83AA7E80;
56 let u = s * 1_000_000_000 + f;
57
58 Duration::new(u / 1_000_000_000, (u % 1_000_000_000) as u32)
60 }
61}