goog_cc/api/units/
timestamp.rs1super::unit_base!(Timestamp);
16
17use std::{fmt, sync::LazyLock, time::{Duration, Instant}};
18use std::ops::*;
19
20use super::TimeDelta;
21
22impl Timestamp {
23 const ONE_SIDED: bool = false;
24
25 pub const fn from_seconds(value: i64) -> Self {
26 Self::from_fraction(1_000_000, value)
27 }
28
29 pub fn from_seconds_float(value: f64) -> Self {
30 Self::from_fraction_float(1_000_000.0, value)
31 }
32
33 pub const fn from_millis(value: i64) -> Self {
34 Self::from_fraction(1_000, value)
35 }
36
37 pub fn from_millis_float(value: f64) -> Self {
38 Self::from_fraction_float(1_000.0, value)
39 }
40
41 pub const fn from_micros(value: i64) -> Self {
42 Self::from_value(value)
43 }
44
45 pub fn from_micros_float(value: f64) -> Self {
46 Self::from_value_float(value)
47 }
48
49 pub const fn seconds(&self) -> i64 {
50 self.to_fraction(1_000_000)
51 }
52
53 pub fn seconds_float(&self) -> f64 {
54 self.to_fraction_float(1_000_000.0)
55 }
56
57 pub const fn ms(&self) -> i64 {
58 self.to_fraction(1_000)
59 }
60
61 pub fn ms_float(&self) -> f64 {
62 self.to_fraction_float(1_000.0)
63 }
64
65 pub const fn us(&self) -> i64 {
66 self.to_value()
67 }
68
69 pub const fn us_float(&self) -> f64 {
70 self.to_value_float()
71 }
72
73 pub const fn seconds_or(&self, fallback_value: i64) -> i64 {
74 self.to_fraction_or(1_000_000, fallback_value)
75 }
76
77 pub const fn ms_or(&self, fallback_value: i64) -> i64 {
78 self.to_fraction_or(1_000, fallback_value)
79 }
80
81 pub const fn us_or(&self, fallback_value: i64) -> i64 {
82 self.to_value_or(fallback_value)
83 }
84}
85
86impl Add<TimeDelta> for Timestamp {
87 type Output = Self;
88
89 fn add(self, delta: TimeDelta) -> Self {
90 if self.is_plus_infinity() || delta.is_plus_infinity() {
91 assert!(!self.is_minus_infinity());
92 assert!(!delta.is_minus_infinity());
93 return Self::plus_infinity();
94 } else if self.is_minus_infinity() || delta.is_minus_infinity() {
95 assert!(!self.is_plus_infinity());
96 assert!(!delta.is_plus_infinity());
97 return Self::minus_infinity();
98 }
99 Timestamp::from_micros(self.us() + delta.us())
100 }
101}
102
103impl Sub<TimeDelta> for Timestamp {
104 type Output = Self;
105
106 fn sub(self, delta: TimeDelta) -> Self {
107 if self.is_plus_infinity() || delta.is_minus_infinity() {
108 assert!(!self.is_minus_infinity());
109 assert!(!delta.is_plus_infinity());
110 return Self::plus_infinity();
111 } else if self.is_minus_infinity() || delta.is_plus_infinity() {
112 assert!(!self.is_plus_infinity());
113 assert!(!delta.is_minus_infinity());
114 return Self::minus_infinity();
115 }
116 Timestamp::from_micros(self.us() - delta.us())
117 }
118}
119
120impl Sub for Timestamp {
121 type Output = TimeDelta;
122
123 fn sub(self, other: Self) -> TimeDelta {
124 if self.is_plus_infinity() || other.is_minus_infinity() {
125 assert!(!self.is_minus_infinity());
126 assert!(!other.is_plus_infinity());
127 return TimeDelta::plus_infinity();
128 } else if self.is_minus_infinity() || other.is_plus_infinity() {
129 assert!(!self.is_plus_infinity());
130 assert!(!other.is_minus_infinity());
131 return TimeDelta::minus_infinity();
132 }
133 TimeDelta::from_micros(self.us() - other.us())
134 }
135}
136
137impl AddAssign<TimeDelta> for Timestamp {
138 fn add_assign(&mut self, delta: TimeDelta) {
139 *self = *self + delta;
140 }
141}
142
143impl SubAssign<TimeDelta> for Timestamp {
144 fn sub_assign(&mut self, delta: TimeDelta) {
145 *self = *self - delta;
146 }
147}
148
149impl fmt::Debug for Timestamp {
150 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151 if self.is_plus_infinity() {
152 write!(f, "+inf ms")
153 } else if self.is_minus_infinity() {
154 write!(f, "-inf ms")
155 } else if self.us() == 0 || (self.us() % 1000) != 0 {
156 write!(f, "{} us", self.us())
157 } else if self.ms() % 1000 != 0 {
158 write!(f, "{} ms", self.ms())
159 } else {
160 write!(f, "{} s", self.seconds())
161 }
162 }
163}
164
165impl From<Instant> for Timestamp {
167 fn from(instant: Instant) -> Self {
168 let r = *REF;
169 if let Some(after) = instant.checked_duration_since(r) {
170 Timestamp::from_micros(after.as_micros() as i64)
171 } else if let Some(before) = r.checked_duration_since(instant) {
172 Timestamp::from_micros(-(before.as_micros() as i64))
173 } else {
174 Timestamp::zero()
175 }
176 }
177}
178
179impl From<Timestamp> for Instant {
180 fn from(timestamp: Timestamp) -> Self {
181 let r = *REF;
182 let duration = Duration::from_micros(timestamp.us().unsigned_abs());
183
184 if timestamp.0 > 0 {
185 r.checked_add(duration).expect("Timestamp is too far in the future")
186 } else {
187 r.checked_sub(duration).expect("Timestamp is from before the program started")
188 }
189 }
190}
191
192static REF: LazyLock<std::time::Instant> = LazyLock::new(|| {
193 std::time::Instant::now()
194});
195
196
197#[cfg(test)]
198mod test {
199 use super::*;
200
201 #[test]
202 fn const_expr() {
203 const VALUE: i64 = 12345;
204 const TIMESTAMP_INF: Timestamp = Timestamp::plus_infinity();
205 assert!(TIMESTAMP_INF.is_infinite());
206 assert!(TIMESTAMP_INF.ms_or(-1) == -1);
207
208 const TIMESTAMP_SECONDS: Timestamp = Timestamp::from_seconds(VALUE);
209 const TIMESTAMP_MS: Timestamp = Timestamp::from_millis(VALUE);
210 const TIMESTAMP_US: Timestamp = Timestamp::from_micros(VALUE);
211
212 assert!(TIMESTAMP_SECONDS.seconds_or(0) == VALUE);
213 assert!(TIMESTAMP_MS.ms_or(0) == VALUE);
214 assert!(TIMESTAMP_US.us_or(0) == VALUE);
215
216 assert!(TIMESTAMP_MS > TIMESTAMP_US);
217
218 assert_eq!(TIMESTAMP_SECONDS.seconds(), VALUE);
219 assert_eq!(TIMESTAMP_MS.ms(), VALUE);
220 assert_eq!(TIMESTAMP_US.us(), VALUE);
221 }
222
223 #[test]
224 fn get_back_same_values() {
225 const VALUE: i64 = 499;
226 assert_eq!(Timestamp::from_millis(VALUE).ms(), VALUE);
227 assert_eq!(Timestamp::from_micros(VALUE).us(), VALUE);
228 assert_eq!(Timestamp::from_seconds(VALUE).seconds(), VALUE);
229 }
230
231 #[test]
232 fn get_different_prefix() {
233 const VALUE: i64 = 3000000;
234 assert_eq!(Timestamp::from_micros(VALUE).seconds(), VALUE / 1000000);
235 assert_eq!(Timestamp::from_millis(VALUE).seconds(), VALUE / 1000);
236 assert_eq!(Timestamp::from_micros(VALUE).ms(), VALUE / 1000);
237
238 assert_eq!(Timestamp::from_millis(VALUE).us(), VALUE * 1000);
239 assert_eq!(Timestamp::from_seconds(VALUE).ms(), VALUE * 1000);
240 assert_eq!(Timestamp::from_seconds(VALUE).us(), VALUE * 1000000);
241 }
242
243 #[test]
244 fn identity_checks() {
245 const VALUE: i64 = 3000;
246
247 assert!(Timestamp::plus_infinity().is_infinite());
248 assert!(Timestamp::minus_infinity().is_infinite());
249 assert!(!Timestamp::from_millis(VALUE).is_infinite());
250
251 assert!(!Timestamp::plus_infinity().is_finite());
252 assert!(!Timestamp::minus_infinity().is_finite());
253 assert!(Timestamp::from_millis(VALUE).is_finite());
254
255 assert!(Timestamp::plus_infinity().is_plus_infinity());
256 assert!(!Timestamp::minus_infinity().is_plus_infinity());
257
258 assert!(Timestamp::minus_infinity().is_minus_infinity());
259 assert!(!Timestamp::plus_infinity().is_minus_infinity());
260 }
261
262 #[test]
263 fn comparison_operators() {
264 const SMALL: i64 = 450;
265 const LARGE: i64 = 451;
266
267 assert_eq!(Timestamp::plus_infinity(), Timestamp::plus_infinity());
268 assert!(Timestamp::plus_infinity() >= Timestamp::plus_infinity());
269 assert!(Timestamp::plus_infinity() > Timestamp::from_millis(LARGE));
270 assert_eq!(Timestamp::from_millis(SMALL), Timestamp::from_millis(SMALL));
271 assert!(Timestamp::from_millis(SMALL) <= Timestamp::from_millis(SMALL));
272 assert!(Timestamp::from_millis(SMALL) >= Timestamp::from_millis(SMALL));
273 assert!(Timestamp::from_millis(SMALL) != Timestamp::from_millis(LARGE));
274 assert!(Timestamp::from_millis(SMALL) <= Timestamp::from_millis(LARGE));
275 assert!(Timestamp::from_millis(SMALL) < Timestamp::from_millis(LARGE));
276 assert!(Timestamp::from_millis(LARGE) >= Timestamp::from_millis(SMALL));
277 assert!(Timestamp::from_millis(LARGE) > Timestamp::from_millis(SMALL));
278 }
279
280 #[test]
281 fn can_be_inititialized_from_large_int() {
282 const MAX_INT: i32 = i32::MAX;
283 assert_eq!(
284 Timestamp::from_seconds(MAX_INT as _).us(),
285 MAX_INT as i64 * 1000000
286 );
287 assert_eq!(
288 Timestamp::from_millis(MAX_INT as _).us(),
289 MAX_INT as i64 * 1000
290 );
291 }
292
293 #[test]
294 fn converts_to_and_from_double() {
295 const MICROS: i64 = 17017;
296 const MICROS_DOUBLE: f64 = MICROS as f64;
297 const MILLIS_DOUBLE: f64 = MICROS as f64 * 1e-3;
298 const SECONDS_DOUBLE: f64 = MILLIS_DOUBLE * 1e-3;
299
300 assert_eq!(
301 Timestamp::from_micros(MICROS).seconds_float(),
302 SECONDS_DOUBLE
303 );
304 assert_eq!(Timestamp::from_seconds_float(SECONDS_DOUBLE).us(), MICROS);
305
306 assert_eq!(Timestamp::from_micros(MICROS).ms_float(), MILLIS_DOUBLE);
307 assert_eq!(Timestamp::from_millis_float(MILLIS_DOUBLE).us(), MICROS);
308
309 assert_eq!(Timestamp::from_micros(MICROS).us_float(), MICROS_DOUBLE);
310 assert_eq!(Timestamp::from_micros_float(MICROS_DOUBLE).us(), MICROS);
311
312 const PLUS_INFINITY: f64 = f64::INFINITY;
313 const MINUS_INFINITY: f64 = -PLUS_INFINITY;
314
315 assert_eq!(Timestamp::plus_infinity().seconds_float(), PLUS_INFINITY);
316 assert_eq!(Timestamp::minus_infinity().seconds_float(), MINUS_INFINITY);
317 assert_eq!(Timestamp::plus_infinity().ms_float(), PLUS_INFINITY);
318 assert_eq!(Timestamp::minus_infinity().ms_float(), MINUS_INFINITY);
319 assert_eq!(Timestamp::plus_infinity().us_float(), PLUS_INFINITY);
320 assert_eq!(Timestamp::minus_infinity().us_float(), MINUS_INFINITY);
321
322 assert!(Timestamp::from_seconds_float(PLUS_INFINITY).is_plus_infinity());
323 assert!(Timestamp::from_seconds_float(MINUS_INFINITY).is_minus_infinity());
324 assert!(Timestamp::from_millis_float(PLUS_INFINITY).is_plus_infinity());
325 assert!(Timestamp::from_millis_float(MINUS_INFINITY).is_minus_infinity());
326 assert!(Timestamp::from_micros_float(PLUS_INFINITY).is_plus_infinity());
327 assert!(Timestamp::from_micros_float(MINUS_INFINITY).is_minus_infinity());
328 }
329
330 #[test]
331 fn timestamp_and_time_delta_math() {
332 const VALUE_A: i64 = 267;
333 const VALUE_B: i64 = 450;
334 const TIME_A: Timestamp = Timestamp::from_millis(VALUE_A);
335 const TIME_B: Timestamp = Timestamp::from_millis(VALUE_B);
336 const DELTA_A: TimeDelta = TimeDelta::from_millis(VALUE_A);
337 const DELTA_B: TimeDelta = TimeDelta::from_millis(VALUE_B);
338
339 assert_eq!((TIME_A - TIME_B), TimeDelta::from_millis(VALUE_A - VALUE_B));
340 assert_eq!(
341 (TIME_B - DELTA_A),
342 Timestamp::from_millis(VALUE_B - VALUE_A)
343 );
344 assert_eq!(
345 (TIME_B + DELTA_A),
346 Timestamp::from_millis(VALUE_B + VALUE_A)
347 );
348
349 let mut mutable_time: Timestamp = TIME_A;
350 mutable_time += DELTA_B;
351 assert_eq!(mutable_time, TIME_A + DELTA_B);
352 mutable_time -= DELTA_B;
353 assert_eq!(mutable_time, TIME_A);
354 }
355
356 #[test]
357 fn infinity_operations() {
358 const VALUE: i64 = 267;
359 const FINITE_TIME: Timestamp = Timestamp::from_millis(VALUE);
360 const FINITE_DELTA: TimeDelta = TimeDelta::from_millis(VALUE);
361 assert!((Timestamp::plus_infinity() + FINITE_DELTA).is_infinite());
362 assert!((Timestamp::plus_infinity() - FINITE_DELTA).is_infinite());
363 assert!((FINITE_TIME + TimeDelta::plus_infinity()).is_infinite());
364 assert!((FINITE_TIME - TimeDelta::minus_infinity()).is_infinite());
365 }
366}