1 use crate::cached_size::CachedSize;
2 use crate::well_known_types::Timestamp;
3 use crate::UnknownFields;
4 use std::time::{Duration, SystemTime};
5 
6 impl Timestamp {
7     /// Unix epoch value of timestamp.
8     pub const UNIX_EPOCH: Timestamp = Timestamp {
9         seconds: 0,
10         nanos: 0,
11         unknown_fields: UnknownFields::INIT,
12         cached_size: CachedSize::INIT,
13     };
14 
15     /// Return current time as `Timestamp`.
now() -> Timestamp16     pub fn now() -> Timestamp {
17         Timestamp::from(SystemTime::now())
18     }
19 }
20 
21 /// Convert from [`Timestamp`].
22 ///
23 /// # Panics
24 ///
25 /// This function panics if given `SystemTime` is outside of `Timestamp` range.
26 impl From<SystemTime> for Timestamp {
from(time: SystemTime) -> Self27     fn from(time: SystemTime) -> Self {
28         match time.duration_since(SystemTime::UNIX_EPOCH) {
29             Ok(since_epoch) => Timestamp {
30                 seconds: since_epoch.as_secs() as i64,
31                 nanos: since_epoch.subsec_nanos() as i32,
32                 ..Default::default()
33             },
34             Err(e) => {
35                 let before_epoch = e.duration();
36                 Timestamp {
37                     seconds: -(before_epoch.as_secs() as i64)
38                         - (before_epoch.subsec_nanos() != 0) as i64,
39                     nanos: (1_000_000_000 - before_epoch.subsec_nanos() as i32) % 1_000_000_000,
40                     ..Default::default()
41                 }
42             }
43         }
44     }
45 }
46 
47 /// Convert into [`SystemTime`].
48 ///
49 /// The conversion could be lossy if `SystemTime` precision is smaller than nanoseconds.
50 ///
51 /// # Panics
52 ///
53 /// This function panics:
54 /// * if given `Timestamp` is outside of `SystemTime` range
55 /// * if `Timestamp` is malformed
56 impl Into<SystemTime> for Timestamp {
into(self) -> SystemTime57     fn into(self) -> SystemTime {
58         if self.seconds >= 0 {
59             let duration =
60                 Duration::from_secs(self.seconds as u64) + Duration::from_nanos(self.nanos as u64);
61             SystemTime::UNIX_EPOCH + duration
62         } else {
63             let duration =
64                 Duration::from_secs(-self.seconds as u64) - Duration::from_nanos(self.nanos as u64);
65             SystemTime::UNIX_EPOCH - duration
66         }
67     }
68 }
69 
70 #[cfg(test)]
71 mod test {
72     use crate::well_known_types::Timestamp;
73     use std::time::Duration;
74     use std::time::SystemTime;
75 
76     #[test]
from_system_time()77     fn from_system_time() {
78         fn to_from(timestamp: Timestamp, system_time: SystemTime) {
79             assert_eq!(timestamp, Timestamp::from(system_time));
80             assert_eq!(system_time, Into::<SystemTime>::into(timestamp));
81         }
82 
83         to_from(Timestamp::UNIX_EPOCH, SystemTime::UNIX_EPOCH);
84         to_from(
85             Timestamp {
86                 seconds: 0,
87                 nanos: 200_000_000,
88                 ..Default::default()
89             },
90             SystemTime::UNIX_EPOCH + Duration::from_millis(200),
91         );
92         to_from(
93             Timestamp {
94                 seconds: 3,
95                 nanos: 200_000_000,
96                 ..Default::default()
97             },
98             SystemTime::UNIX_EPOCH + Duration::from_millis(3_200),
99         );
100         to_from(
101             Timestamp {
102                 seconds: -1,
103                 nanos: 800_000_000,
104                 ..Default::default()
105             },
106             SystemTime::UNIX_EPOCH - Duration::from_millis(200),
107         );
108         to_from(
109             Timestamp {
110                 seconds: -4,
111                 nanos: 800_000_000,
112                 ..Default::default()
113             },
114             SystemTime::UNIX_EPOCH - Duration::from_millis(3_200),
115         );
116     }
117 }
118