ros2_client/
steady_time.rs1use std::{
20 cmp::Ordering,
21 convert::TryFrom,
22 fmt,
23 ops::{Add, Sub},
24 time::{Duration, Instant},
25};
26
27use chrono::{DateTime, Utc};
28
29use crate::ROSTime;
30
31#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug)]
36pub struct Time {
37 instant: Instant,
38}
39
40impl Time {
41 pub fn now() -> Time {
42 Self {
43 instant: Instant::now(),
44 }
45 }
46
47 pub fn now_with_ros_time() -> (Time, ROSTime) {
49 let (st, ct) = Self::now_with_utc();
50 let ros_time = ROSTime::try_from(ct)
51 .unwrap_or(ROSTime::ZERO);
53 (st, ros_time)
54 }
55
56 #[doc(hidden)]
57 pub fn now_with_utc() -> (Time, DateTime<Utc>) {
58 let m0 = Self::now();
59 let utc = Utc::now();
60 let m1 = Self::now();
61 let diff = m1 - m0;
62 (m0 + TimeDiff::from_nanos(diff.as_nanos() / 2), utc)
67 }
68} impl fmt::Display for Time {
71 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
72 fmt::Debug::fmt(self, fmt)
74 }
75}
76
77impl Sub for Time {
78 type Output = TimeDiff;
79
80 fn sub(self, other: Time) -> TimeDiff {
81 self
82 .instant
83 .checked_duration_since(other.instant)
84 .map(|duration| TimeDiff {
86 duration,
87 is_negative: false,
88 })
89 .unwrap_or_else(|| TimeDiff {
90 duration: other.instant.saturating_duration_since(self.instant),
91 is_negative: true,
92 })
93 }
94}
95
96impl Sub<TimeDiff> for Time {
98 type Output = Time;
99
100 fn sub(self, diff: TimeDiff) -> Time {
101 if diff.is_negative {
102 Time {
103 instant: self.instant - diff.duration,
104 }
105 } else {
106 Time {
107 instant: self.instant + diff.duration,
108 }
109 }
110 }
111}
112
113impl Add<TimeDiff> for Time {
115 type Output = Time;
116
117 fn add(self, diff: TimeDiff) -> Time {
118 if diff.is_negative {
119 Time {
120 instant: self.instant + diff.duration,
121 }
122 } else {
123 Time {
124 instant: self.instant - diff.duration,
125 }
126 }
127 }
128}
129
130#[derive(Clone, Copy, Debug, Eq, PartialEq)]
132pub struct TimeDiff {
133 duration: Duration,
134 is_negative: bool, }
136
137#[derive(Debug, Clone, Copy)]
138pub struct NegativetimeDiffError {}
139
140impl TimeDiff {
141 pub const fn from_nanos(nanos: i64) -> TimeDiff {
142 if nanos >= 0 {
143 TimeDiff {
144 duration: Duration::from_nanos(nanos as u64),
145 is_negative: false,
146 }
147 } else {
148 TimeDiff {
149 duration: Duration::from_nanos(-nanos as u64),
150 is_negative: true,
151 }
152 }
153 }
154
155 pub const fn from_millis(millis: i64) -> TimeDiff {
156 Self::from_nanos(millis * 1_000_000)
157 }
158
159 pub const fn from_secs(secs: i64) -> TimeDiff {
160 Self::from_nanos(secs * 1_000_000_000)
161 }
162
163 pub const fn as_nanos(self) -> i64 {
164 let n = self.duration.as_nanos();
165 let n = if n > (i64::MAX as u128) {
166 i64::MAX
167 } else {
168 n as i64
169 };
170 if self.is_negative {
171 -n
172 } else {
173 n
174 }
175 }
176
177 pub const fn as_millis(self) -> i64 {
178 self.as_nanos() / 1_000_000
179 }
180
181 #[allow(dead_code)]
182 pub const fn as_seconds(self) -> i64 {
183 self.as_nanos() / 1_000_000_000
184 }
185
186 pub fn as_duration(self) -> Result<Duration, NegativetimeDiffError> {
187 if self.is_negative {
188 Err(NegativetimeDiffError {})
189 } else {
190 Ok(self.duration)
191 }
192 }
193
194 pub fn as_saturating_duration(self) -> Duration {
195 if self.is_negative {
196 Duration::ZERO
197 } else {
198 self.duration
199 }
200 }
201}
202
203impl Ord for TimeDiff {
204 fn cmp(&self, other: &Self) -> Ordering {
205 match (self.is_negative, other.is_negative) {
206 (false, false) => self.duration.cmp(&other.duration),
207 (true, true) => self.duration.cmp(&other.duration).reverse(),
208 (false, true) => Ordering::Greater,
209 (true, false) => Ordering::Less,
210 }
211 }
212}
213
214impl PartialOrd for TimeDiff {
215 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
216 Some(self.cmp(other))
217 }
218}
219
220impl fmt::Display for TimeDiff {
221 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
222 fmt::Debug::fmt(self, fmt)
224 }
225}
226
227impl Add for TimeDiff {
228 type Output = TimeDiff;
229 fn add(self, other: TimeDiff) -> TimeDiff {
230 Self::from_nanos(self.as_nanos() + other.as_nanos())
231 }
232}
233
234impl Sub for TimeDiff {
235 type Output = TimeDiff;
236 fn sub(self, other: TimeDiff) -> TimeDiff {
237 Self::from_nanos(self.as_nanos() - other.as_nanos())
238 }
239}