statime/time/
instant.rs

1//! Implementation of the [Time] type
2
3use core::{
4    fmt::Display,
5    ops::{Add, AddAssign, Sub, SubAssign},
6};
7
8use fixed::{
9    traits::{LosslessTryInto, LossyInto, ToFixed},
10    types::{U112F16, U96F32},
11};
12
13use super::duration::Duration;
14use crate::datastructures::common::WireTimestamp;
15
16/// Time represents a specific moment in time.
17///
18/// The starting 0 point depends on the timescale being used by PTP, but
19/// for most uses will be the unix epoch.
20#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
21pub struct Time {
22    /// Time in nanos since start of timescale
23    inner: U96F32,
24}
25
26impl Time {
27    /// Create an instance with the given amount of seconds from the origin
28    pub fn from_secs(secs: u64) -> Self {
29        let inner = secs.to_fixed::<U96F32>() * 1_000_000_000.to_fixed::<U96F32>();
30        Self { inner }
31    }
32    /// Create an instance with the given amount of milliseconds from the origin
33    pub fn from_millis(millis: u64) -> Self {
34        let inner = millis.to_fixed::<U96F32>() * 1_000_000.to_fixed::<U96F32>();
35        Self { inner }
36    }
37    /// Create an instance with the given amount of microseconds from the origin
38    pub fn from_micros(micros: u64) -> Self {
39        let inner = micros.to_fixed::<U96F32>() * 1_000.to_fixed::<U96F32>();
40        Self { inner }
41    }
42    /// Create an instance with the given amount of nanoseconds from the origin
43    pub fn from_nanos(nanos: u64) -> Self {
44        let inner = nanos.to_fixed::<U96F32>();
45        Self { inner }
46    }
47    /// Create an instance with the given amount of nanoseconds from the origin,
48    /// using a fixed point number so the subnanoseconds can be specified as
49    /// well
50    pub fn from_fixed_nanos<F: ToFixed>(nanos: F) -> Self {
51        Self {
52            inner: nanos.to_fixed(),
53        }
54    }
55
56    /// Construdt a [`Duration`] from nanoseconds and fractions of nanosecods
57    ///
58    /// `subnanos` are the bits after the decimal seperator. e.g. 0.5ns = `1 <<
59    /// 31`
60    ///
61    /// # Example
62    /// ```
63    /// use az::Az;
64    /// use fixed::types::I96F32;
65    /// # use statime::time::Time;
66    /// assert_eq!(Time::from_nanos_subnanos(0, 1 << 31), Time::from_fixed_nanos(0.5.az::<I96F32>()))
67    /// ```
68    pub fn from_nanos_subnanos(nanos: u64, subnanos: u32) -> Self {
69        let bits = ((nanos as u128) << 32) | (subnanos as u128);
70        let inner = U96F32::from_bits(bits);
71        Self { inner }
72    }
73
74    /// Get the total amount of nanoseconds since the origin
75    pub fn nanos(&self) -> U96F32 {
76        self.inner
77    }
78    /// Get all the nanoseconds that are under a second
79    pub fn subsec_nanos(&self) -> u32 {
80        (self.inner % 1_000_000_000.to_fixed::<U96F32>()).to_num()
81    }
82    /// Get the total amount of seconds since the origin
83    pub fn secs(&self) -> u64 {
84        (self.inner / 1_000_000_000.to_fixed::<U96F32>()).to_num()
85    }
86    // Get the subnanosecond amount
87    pub(crate) fn subnano(&self) -> crate::datastructures::common::TimeInterval {
88        let inter: U112F16 = self.inner.frac().lossy_into();
89        // unwrap is ok since always less than 1.
90        crate::datastructures::common::TimeInterval(inter.lossless_try_into().unwrap())
91    }
92}
93
94impl From<WireTimestamp> for Time {
95    fn from(ts: WireTimestamp) -> Self {
96        Self::from_fixed_nanos(ts.seconds as i128 * 1_000_000_000i128 + ts.nanos as i128)
97    }
98}
99
100impl Add<Duration> for Time {
101    type Output = Time;
102
103    fn add(self, rhs: Duration) -> Self::Output {
104        if rhs.nanos().is_negative() {
105            Time {
106                inner: self.nanos() - rhs.nanos().unsigned_abs(),
107            }
108        } else {
109            Time {
110                inner: self.nanos() + rhs.nanos().unsigned_abs(),
111            }
112        }
113    }
114}
115
116impl AddAssign<Duration> for Time {
117    fn add_assign(&mut self, rhs: Duration) {
118        *self = *self + rhs;
119    }
120}
121
122impl Sub<Duration> for Time {
123    type Output = Time;
124
125    fn sub(self, rhs: Duration) -> Self::Output {
126        self + -rhs
127    }
128}
129
130impl SubAssign<Duration> for Time {
131    fn sub_assign(&mut self, rhs: Duration) {
132        *self = *self - rhs;
133    }
134}
135
136impl Sub<Time> for Time {
137    type Output = Duration;
138
139    fn sub(self, rhs: Time) -> Self::Output {
140        Duration::from_fixed_nanos(self.inner) - Duration::from_fixed_nanos(rhs.inner)
141    }
142}
143
144impl Display for Time {
145    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
146        write!(f, "{}", self.inner)
147    }
148}
149
150#[cfg(test)]
151mod tests {
152    use super::*;
153
154    #[test]
155    fn values() {
156        assert_eq!(
157            Time::from_secs(10).nanos(),
158            10_000_000_000u64.to_fixed::<U96F32>()
159        );
160        assert_eq!(
161            Time::from_millis(10).nanos(),
162            10_000_000u64.to_fixed::<U96F32>()
163        );
164        assert_eq!(
165            Time::from_micros(10).nanos(),
166            10_000u64.to_fixed::<U96F32>()
167        );
168        assert_eq!(Time::from_nanos(10).nanos(), 10u64.to_fixed::<U96F32>());
169        assert_eq!(
170            Time::from_fixed_nanos(10.123f64).nanos(),
171            10.123f64.to_fixed::<U96F32>()
172        );
173        assert_eq!(Time::from_secs(10).secs(), 10);
174        assert_eq!(Time::from_millis(10).secs(), 0);
175        assert_eq!(Time::from_millis(1001).secs(), 1);
176    }
177}