firebase_rs_sdk/firestore/model/
timestamp.rs1use std::cmp::Ordering;
2use std::time::{Duration, SystemTime, UNIX_EPOCH};
3
4#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
5pub struct Timestamp {
6 pub seconds: i64,
7 pub nanos: i32,
8}
9
10impl Timestamp {
11 pub fn new(seconds: i64, nanos: i32) -> Self {
12 let mut timestamp = Self { seconds, nanos };
13 timestamp.normalize();
14 timestamp
15 }
16
17 pub fn now() -> Self {
18 let duration = SystemTime::now()
19 .duration_since(UNIX_EPOCH)
20 .unwrap_or_else(|_| Duration::from_secs(0));
21 Self {
22 seconds: duration.as_secs() as i64,
23 nanos: duration.subsec_nanos() as i32,
24 }
25 }
26
27 pub fn from_system_time(time: SystemTime) -> Self {
28 match time.duration_since(UNIX_EPOCH) {
29 Ok(duration) => Self {
30 seconds: duration.as_secs() as i64,
31 nanos: duration.subsec_nanos() as i32,
32 },
33 Err(err) => {
34 let duration = err.duration();
35 Self {
36 seconds: -(duration.as_secs() as i64),
37 nanos: -(duration.subsec_nanos() as i32),
38 }
39 }
40 }
41 }
42
43 pub fn to_system_time(&self) -> SystemTime {
44 if self.seconds >= 0 {
45 UNIX_EPOCH
46 + Duration::from_secs(self.seconds as u64)
47 + Duration::from_nanos(self.nanos as u64)
48 } else {
49 UNIX_EPOCH
50 - Duration::from_secs((-self.seconds) as u64)
51 - Duration::from_nanos(self.nanos.unsigned_abs() as u64)
52 }
53 }
54
55 fn normalize(&mut self) {
56 let extra_seconds = self.nanos.div_euclid(1_000_000_000);
57 self.seconds += extra_seconds as i64;
58 self.nanos = self.nanos.rem_euclid(1_000_000_000);
59 if self.seconds > 0 && self.nanos < 0 {
60 self.seconds -= 1;
61 self.nanos += 1_000_000_000;
62 }
63 }
64}
65
66impl PartialOrd for Timestamp {
67 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
68 Some(self.cmp(other))
69 }
70}
71
72impl Ord for Timestamp {
73 fn cmp(&self, other: &Self) -> Ordering {
74 match self.seconds.cmp(&other.seconds) {
75 Ordering::Equal => self.nanos.cmp(&other.nanos),
76 ordering => ordering,
77 }
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn normalize_nanoseconds() {
87 let timestamp = Timestamp::new(1, 1_500_000_000);
88 assert_eq!(timestamp.seconds, 2);
89 assert_eq!(timestamp.nanos, 500_000_000);
90 }
91
92 #[test]
93 fn ordering() {
94 let earlier = Timestamp::new(1, 0);
95 let later = Timestamp::new(2, 0);
96 assert!(earlier < later);
97 }
98}