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