use crate::cached_size::CachedSize; use crate::well_known_types::Timestamp; use crate::UnknownFields; use std::time::{Duration, SystemTime}; impl Timestamp { /// Unix epoch value of timestamp. pub const UNIX_EPOCH: Timestamp = Timestamp { seconds: 0, nanos: 0, unknown_fields: UnknownFields::INIT, cached_size: CachedSize::INIT, }; /// Return current time as `Timestamp`. pub fn now() -> Timestamp { Timestamp::from(SystemTime::now()) } } /// Convert from [`Timestamp`]. /// /// # Panics /// /// This function panics if given `SystemTime` is outside of `Timestamp` range. impl From for Timestamp { fn from(time: SystemTime) -> Self { match time.duration_since(SystemTime::UNIX_EPOCH) { Ok(since_epoch) => Timestamp { seconds: since_epoch.as_secs() as i64, nanos: since_epoch.subsec_nanos() as i32, ..Default::default() }, Err(e) => { let before_epoch = e.duration(); Timestamp { seconds: -(before_epoch.as_secs() as i64) - (before_epoch.subsec_nanos() != 0) as i64, nanos: (1_000_000_000 - before_epoch.subsec_nanos() as i32) % 1_000_000_000, ..Default::default() } } } } } /// Convert into [`SystemTime`]. /// /// The conversion could be lossy if `SystemTime` precision is smaller than nanoseconds. /// /// # Panics /// /// This function panics: /// * if given `Timestamp` is outside of `SystemTime` range /// * if `Timestamp` is malformed impl Into for Timestamp { fn into(self) -> SystemTime { if self.seconds >= 0 { let duration = Duration::from_secs(self.seconds as u64) + Duration::from_nanos(self.nanos as u64); SystemTime::UNIX_EPOCH + duration } else { let duration = Duration::from_secs(-self.seconds as u64) - Duration::from_nanos(self.nanos as u64); SystemTime::UNIX_EPOCH - duration } } } #[cfg(test)] mod test { use crate::well_known_types::Timestamp; use std::time::Duration; use std::time::SystemTime; #[test] fn from_system_time() { fn to_from(timestamp: Timestamp, system_time: SystemTime) { assert_eq!(timestamp, Timestamp::from(system_time)); assert_eq!(system_time, Into::::into(timestamp)); } to_from(Timestamp::UNIX_EPOCH, SystemTime::UNIX_EPOCH); to_from( Timestamp { seconds: 0, nanos: 200_000_000, ..Default::default() }, SystemTime::UNIX_EPOCH + Duration::from_millis(200), ); to_from( Timestamp { seconds: 3, nanos: 200_000_000, ..Default::default() }, SystemTime::UNIX_EPOCH + Duration::from_millis(3_200), ); to_from( Timestamp { seconds: -1, nanos: 800_000_000, ..Default::default() }, SystemTime::UNIX_EPOCH - Duration::from_millis(200), ); to_from( Timestamp { seconds: -4, nanos: 800_000_000, ..Default::default() }, SystemTime::UNIX_EPOCH - Duration::from_millis(3_200), ); } }