1use std::cmp;
3use std::fmt;
4use std::time::Duration;
5
6pub struct DurationFmt(pub Duration);
7
8impl DurationFmt {
9 pub fn from_nanos(nanos: u64) -> DurationFmt {
10 DurationFmt(Duration::from_nanos(nanos))
11 }
12
13 #[inline(always)]
14 fn duration(&self) -> Duration {
15 self.0
16 }
17
18 #[inline(always)]
19 fn pure_nanos(&self) -> u128 {
20 self.0.as_nanos() % Duration::from_micros(1).as_nanos()
21 }
22
23 #[inline(always)]
24 fn pure_micros(&self) -> u128 {
25 (self.0.as_nanos() % Duration::from_millis(1).as_nanos())
26 / Duration::from_micros(1).as_nanos()
27 }
28
29 #[inline(always)]
30 fn pure_millis(&self) -> u128 {
31 (self.0.as_nanos() % Duration::from_secs(1).as_nanos())
32 / Duration::from_millis(1).as_nanos()
33 }
34
35 #[inline(always)]
36 fn pure_secs_as_f64(&self) -> f64 {
37 ((self.0.as_nanos() % Duration::from_secs(60).as_nanos()) as f64)
38 / (Duration::from_secs(1).as_nanos() as f64)
39 }
40
41 #[inline(always)]
42 fn pure_mins(&self) -> u128 {
43 (self.0.as_nanos() % Duration::from_secs(60 * 60).as_nanos())
44 / Duration::from_secs(60).as_nanos()
45 }
46
47 #[inline(always)]
48 fn pure_hours(&self) -> u128 {
49 self.0.as_nanos() / Duration::from_secs(60 * 60).as_nanos()
50 }
51}
52
53impl cmp::PartialEq for DurationFmt {
54 fn eq(&self, other: &Self) -> bool {
55 self.duration() == other.duration()
56 }
57}
58
59impl From<Duration> for DurationFmt {
60 #[inline(always)]
61 fn from(d: Duration) -> Self {
62 DurationFmt(d)
63 }
64}
65
66impl fmt::Display for DurationFmt {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 match self.duration() {
69 d if d <= Duration::from_micros(1) => write!(f, "{}ns", self.pure_nanos()),
70 d if d <= Duration::from_millis(1) => {
71 let ns = self.pure_nanos();
72 let mcs = self.pure_micros();
73
74 match ns {
75 0 => write!(f, "{}us", mcs),
76 _ => write!(f, "{}us{}ns", mcs, ns),
77 }
78 }
79 d if d <= (Duration::from_secs(1) / 10) => {
80 let mcs = self.pure_micros();
81 let ms = self.pure_millis();
82
83 match mcs {
84 0 => write!(f, "{}ms", ms),
85 _ => write!(f, "{}ms{}us", ms, mcs),
86 }
87 }
88 _ => {
89 let h = self.pure_hours();
90 let m = self.pure_mins();
91 let s = self.pure_secs_as_f64();
92
93 if h != 0 {
94 write!(f, "{}h", h)?;
95 }
96
97 if m != 0 {
98 write!(f, "{}m", m)?;
99 }
100
101 if s != 0.0 {
102 write!(f, "{:.2}s", s)
103 } else {
104 Ok(())
105 }
106 }
107 }
108 }
109}
110
111impl fmt::Debug for DurationFmt {
112 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 write!(f, "{}", self)
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use super::DurationFmt;
120
121 use std::time::Duration;
122
123 #[test]
124 fn fmt_ns() {
125 assert_eq!(format!("{}", DurationFmt::from_nanos(1)), "1ns");
126 }
127
128 #[test]
129 fn fmt_h_m_s() {
130 assert_eq!(
131 format!(
132 "{}",
133 DurationFmt::from(
134 Duration::from_secs(10*3600) + Duration::from_secs(30*60) + Duration::from_secs(15) + Duration::from_millis(100) )
139 ),
140 "10h30m15.10s"
141 );
142 }
143
144 #[test]
145 fn fmt_ms_us() {
146 assert_eq!(
147 format!(
148 "{}",
149 DurationFmt::from(
150 Duration::from_millis(23) + Duration::from_micros(17) + Duration::from_nanos(40) )
154 ),
155 "23ms17us"
156 );
157 }
158}