1use std::fmt;
5
6pub const NANOS_PER_SECOND: u64 = 1_000_000_000;
8pub const NANOS_PER_MILLISECOND: u64 = 1_000_000;
10
11pub enum ClockType {
13 Monotonic,
15 Real,
17 ProcessCpu,
19 ThreadCpu,
21}
22
23impl From<ClockType> for libc::clockid_t {
24 fn from(clock_type: ClockType) -> Self {
25 match clock_type {
26 ClockType::Monotonic => libc::CLOCK_MONOTONIC,
27 ClockType::Real => libc::CLOCK_REALTIME,
28 ClockType::ProcessCpu => libc::CLOCK_PROCESS_CPUTIME_ID,
29 ClockType::ThreadCpu => libc::CLOCK_THREAD_CPUTIME_ID,
30 }
31 }
32}
33
34pub struct LocalTime {
36 sec: i32,
38 min: i32,
40 hour: i32,
42 mday: i32,
44 mon: i32,
46 year: i32,
48 nsec: i64,
50}
51
52impl LocalTime {
53 pub fn now() -> LocalTime {
55 let mut timespec = libc::timespec {
56 tv_sec: 0,
57 tv_nsec: 0,
58 };
59 let mut tm: libc::tm = libc::tm {
60 tm_sec: 0,
61 tm_min: 0,
62 tm_hour: 0,
63 tm_mday: 0,
64 tm_mon: 0,
65 tm_year: 0,
66 tm_wday: 0,
67 tm_yday: 0,
68 tm_isdst: 0,
69 tm_gmtoff: 0,
70 tm_zone: std::ptr::null(),
71 };
72
73 unsafe {
75 libc::clock_gettime(libc::CLOCK_REALTIME, &mut timespec);
76 libc::localtime_r(×pec.tv_sec, &mut tm);
77 }
78
79 LocalTime {
80 sec: tm.tm_sec,
81 min: tm.tm_min,
82 hour: tm.tm_hour,
83 mday: tm.tm_mday,
84 mon: tm.tm_mon,
85 year: tm.tm_year,
86 nsec: timespec.tv_nsec,
87 }
88 }
89}
90
91impl fmt::Display for LocalTime {
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 write!(
94 f,
95 "{}-{:02}-{:02}T{:02}:{:02}:{:02}.{:09}",
96 self.year + 1900,
97 self.mon + 1,
98 self.mday,
99 self.hour,
100 self.min,
101 self.sec,
102 self.nsec
103 )
104 }
105}
106
107#[derive(Clone)]
109pub struct TimestampUs {
110 pub time_us: u64,
112 pub cputime_us: u64,
114}
115
116impl Default for TimestampUs {
117 fn default() -> TimestampUs {
118 TimestampUs {
119 time_us: get_time_us(ClockType::Monotonic),
120 cputime_us: get_time_us(ClockType::ProcessCpu),
121 }
122 }
123}
124
125pub fn now_cputime_us() -> u64 {
127 get_time_us(ClockType::ProcessCpu)
128}
129
130pub fn timestamp_cycles() -> u64 {
134 #[cfg(target_arch = "x86_64")]
135 unsafe {
137 std::arch::x86_64::_rdtsc() as u64
138 }
139 #[cfg(not(target_arch = "x86_64"))]
140 {
141 get_time_ns(ClockType::Monotonic)
142 }
143}
144
145pub fn get_time_ns(clock_type: ClockType) -> u64 {
151 let mut time_struct = libc::timespec {
152 tv_sec: 0,
153 tv_nsec: 0,
154 };
155 unsafe { libc::clock_gettime(clock_type.into(), &mut time_struct) };
157 seconds_to_nanoseconds(time_struct.tv_sec).expect("Time conversion overflow") as u64
158 + (time_struct.tv_nsec as u64)
159}
160
161pub fn get_time_us(clock_type: ClockType) -> u64 {
167 get_time_ns(clock_type) / 1000
168}
169
170pub fn get_time_ms(clock_type: ClockType) -> u64 {
176 get_time_ns(clock_type) / NANOS_PER_MILLISECOND
177}
178
179pub fn seconds_to_nanoseconds(value: i64) -> Option<i64> {
186 value.checked_mul(NANOS_PER_SECOND as i64)
187}
188
189#[cfg(test)]
190mod tests {
191 use super::*;
192
193 #[test]
194 fn test_get_time() {
195 for _ in 0..1000 {
196 assert!(get_time_ns(ClockType::Monotonic) <= get_time_ns(ClockType::Monotonic));
197 }
198
199 for _ in 0..1000 {
200 assert!(get_time_ns(ClockType::ProcessCpu) <= get_time_ns(ClockType::ProcessCpu));
201 }
202
203 for _ in 0..1000 {
204 assert!(get_time_ns(ClockType::ThreadCpu) <= get_time_ns(ClockType::ThreadCpu));
205 }
206
207 assert_ne!(get_time_ns(ClockType::Real), 0);
208 assert_ne!(get_time_us(ClockType::Real), 0);
209 assert!(get_time_ns(ClockType::Real) / 1000 <= get_time_us(ClockType::Real));
210 assert!(
211 get_time_ns(ClockType::Real) / NANOS_PER_MILLISECOND <= get_time_ms(ClockType::Real)
212 );
213 }
214
215 #[test]
216 fn test_local_time_display() {
217 let local_time = LocalTime {
218 sec: 30,
219 min: 15,
220 hour: 10,
221 mday: 4,
222 mon: 6,
223 year: 119,
224 nsec: 123_456_789,
225 };
226 assert_eq!(
227 String::from("2019-07-04T10:15:30.123456789"),
228 local_time.to_string()
229 );
230
231 let local_time = LocalTime {
232 sec: 5,
233 min: 5,
234 hour: 5,
235 mday: 23,
236 mon: 7,
237 year: 44,
238 nsec: 123,
239 };
240 assert_eq!(
241 String::from("1944-08-23T05:05:05.000000123"),
242 local_time.to_string()
243 );
244
245 let local_time = LocalTime::now();
246 assert!(local_time.mon >= 0 && local_time.mon <= 11);
247 }
248
249 #[test]
250 fn test_seconds_to_nanoseconds() {
251 assert_eq!(
252 seconds_to_nanoseconds(100).unwrap() as u64,
253 100 * NANOS_PER_SECOND
254 );
255
256 assert!(seconds_to_nanoseconds(9_223_372_037).is_none());
257 }
258}