Skip to main content

packet_strata/
timestamp.rs

1use chrono::{DateTime};
2use serde::{Deserialize, Serialize};
3use std::{
4    fmt,
5    ops::{Add, Div, Mul, Sub},
6};
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Serialize, Deserialize)]
9pub struct Timestamp(pub u64); // Nanoseconds since epoch
10
11impl Timestamp {
12    pub const ZERO: Self = Timestamp(0);
13
14    #[inline]
15    pub fn from_nanos(nanos: u64) -> Self {
16        Self(nanos)
17    }
18
19    #[inline]
20    pub fn as_nanos(&self) -> u64 {
21        self.0
22    }
23
24    pub fn as_secs_f64(&self) -> f64 {
25        self.0 as f64 / 1_000_000_000.0
26    }
27}
28
29impl fmt::Display for Timestamp {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        if let Some(date_time) = DateTime::from_timestamp(
32            (self.0 / 1_000_000_000) as i64,
33            (self.0 % 1_000_000_000) as u32,
34        ) {
35            if !f.alternate() {
36                return write!(f, "{}", date_time.format("%Y-%m-%d %H:%M:%S%.6f UTC"));
37            }
38        }
39
40        write!(
41            f,
42            "{}.{:09}",
43            self.0 / 1_000_000_000,
44            self.0 % 1_000_000_000
45        )
46    }
47}
48
49#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Serialize, Deserialize)]
50pub struct Interval(pub i64); // Signed nanoseconds
51
52impl Interval {
53    pub const ZERO: Self = Interval(0);
54
55    #[inline]
56    pub fn from_nanos(nanos: i64) -> Self {
57        Self(nanos)
58    }
59
60    #[inline]
61    pub fn as_nanos(&self) -> i64 {
62        self.0
63    }
64
65    pub fn as_secs_f64(&self) -> f64 {
66        self.0 as f64 / 1_000_000_000.0
67    }
68
69    pub fn abs(&self) -> Self {
70        Self(self.0.abs())
71    }
72}
73
74impl fmt::Display for Interval {
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76        let total_nanos = self.0.abs();
77        let secs = total_nanos / 1_000_000_000;
78        let nanos = total_nanos % 1_000_000_000;
79        let sign = if self.0 < 0 { "-" } else { "" };
80        write!(f, "{}{}.{:09}", sign, secs, nanos)
81    }
82}
83
84// --- Timestamp Operations ---
85
86impl Add<Interval> for Timestamp {
87    type Output = Timestamp;
88    #[inline]
89    fn add(self, rhs: Interval) -> Self::Output {
90        Timestamp(self.0.saturating_add_signed(rhs.0))
91    }
92}
93
94impl Sub<Interval> for Timestamp {
95    type Output = Timestamp;
96    #[inline]
97    fn sub(self, rhs: Interval) -> Self::Output {
98        Timestamp(self.0.saturating_sub_signed(rhs.0))
99    }
100}
101
102impl Sub for Timestamp {
103    type Output = Interval;
104    #[inline]
105    fn sub(self, rhs: Self) -> Self::Output {
106        if self.0 >= rhs.0 {
107            Interval((self.0 - rhs.0) as i64)
108        } else {
109            Interval(-((rhs.0 - self.0) as i64))
110        }
111    }
112}
113
114// --- Interval Operations ---
115
116impl Add for Interval {
117    type Output = Interval;
118    #[inline]
119    fn add(self, rhs: Self) -> Self::Output {
120        Interval(self.0.saturating_add(rhs.0))
121    }
122}
123
124impl Sub for Interval {
125    type Output = Interval;
126    #[inline]
127    fn sub(self, rhs: Self) -> Self::Output {
128        Interval(self.0.saturating_sub(rhs.0))
129    }
130}
131
132impl Mul<f64> for Interval {
133    type Output = Interval;
134    #[inline]
135    fn mul(self, rhs: f64) -> Self::Output {
136        Interval((self.0 as f64 * rhs) as i64)
137    }
138}
139
140impl Div<i64> for Interval {
141    type Output = Interval;
142    #[inline]
143    fn div(self, rhs: i64) -> Self::Output {
144        Interval(self.0 / rhs)
145    }
146}
147
148impl Add<Timestamp> for Interval {
149    type Output = Timestamp;
150    #[inline]
151    fn add(self, rhs: Timestamp) -> Self::Output {
152        rhs + self
153    }
154}