1use core::{
2 fmt::{self, Debug, Display},
3 ops::{Add, AddAssign, Sub, SubAssign},
4};
5
6#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
10pub struct Duration {
11 nanos: i128,
12}
13
14const NANOS_IN_MICROS: i128 = 1000;
15const NANOS_IN_MILLIS: i128 = NANOS_IN_MICROS * 1000;
16const NANOS_IN_SECS: i128 = NANOS_IN_MILLIS * 1000;
17const NANOS_IN_MINS: i128 = NANOS_IN_SECS * 60;
18const NANOS_IN_HOURS: i128 = NANOS_IN_MINS * 60;
19const NANOS_IN_DAYS: i128 = NANOS_IN_HOURS * 24;
20const NANOS_IN_WEEKS: i128 = NANOS_IN_DAYS * 7;
21
22impl Duration {
23 pub const ZERO: Duration = Duration { nanos: 0 };
25
26 pub const fn from_nanos(nanos: i128) -> Duration {
30 Duration { nanos }
31 }
32
33 pub const fn from_micros(micros: i64) -> Duration {
37 Duration {
38 nanos: micros as i128 * NANOS_IN_MICROS,
39 }
40 }
41
42 pub const fn from_millis(millis: i64) -> Duration {
46 Duration {
47 nanos: millis as i128 * NANOS_IN_MILLIS,
48 }
49 }
50
51 pub const fn from_secs(secs: i64) -> Duration {
55 Duration {
56 nanos: secs as i128 * NANOS_IN_SECS,
57 }
58 }
59
60 pub const fn from_minutes(mins: i64) -> Duration {
64 Duration {
65 nanos: mins as i128 * NANOS_IN_MINS,
66 }
67 }
68
69 pub const fn from_hours(hours: i64) -> Duration {
73 Duration {
74 nanos: hours as i128 * NANOS_IN_HOURS,
75 }
76 }
77
78 pub const fn from_days(days: i64) -> Duration {
82 Duration {
83 nanos: days as i128 * NANOS_IN_DAYS,
84 }
85 }
86
87 pub const fn from_weeks(weeks: i64) -> Duration {
91 Duration {
92 nanos: weeks as i128 * NANOS_IN_WEEKS,
93 }
94 }
95
96 pub const fn nanos(&self) -> i128 {
98 self.nanos
99 }
100
101 pub const fn micros(&self) -> i128 {
103 self.nanos / NANOS_IN_MICROS
104 }
105
106 pub const fn millis(&self) -> i128 {
108 self.nanos / NANOS_IN_MILLIS
109 }
110
111 pub const fn secs(&self) -> i128 {
113 self.nanos / NANOS_IN_SECS
114 }
115
116 pub const fn mins(&self) -> i128 {
118 self.nanos / NANOS_IN_MINS
119 }
120
121 pub const fn hours(&self) -> i128 {
123 self.nanos / NANOS_IN_HOURS
124 }
125
126 pub const fn days(&self) -> i128 {
128 self.nanos / NANOS_IN_DAYS
129 }
130
131 pub const fn weeks(&self) -> i128 {
133 self.nanos / NANOS_IN_WEEKS
134 }
135
136 pub fn checked_add(&self, rhs: &Duration) -> Option<Self> {
138 self.nanos
139 .checked_add(rhs.nanos)
140 .map(|nanos| Duration { nanos })
141 }
142
143 pub fn checked_sub(&self, rhs: &Duration) -> Option<Self> {
145 self.nanos
146 .checked_sub(rhs.nanos)
147 .map(|nanos| Duration { nanos })
148 }
149}
150
151impl Add<Duration> for Duration {
152 type Output = Duration;
153
154 fn add(self, rhs: Self) -> Self::Output {
155 self.checked_add(&rhs)
156 .expect("overflow while adding durations")
157 }
158}
159
160impl AddAssign<Duration> for Duration {
161 fn add_assign(&mut self, rhs: Duration) {
162 *self = *self + rhs
163 }
164}
165
166impl Sub<Duration> for Duration {
167 type Output = Duration;
168
169 fn sub(self, rhs: Duration) -> Self::Output {
170 self.checked_sub(&rhs)
171 .expect("overflow while subtracting durations")
172 }
173}
174
175impl SubAssign<Duration> for Duration {
176 fn sub_assign(&mut self, rhs: Duration) {
177 *self = *self - rhs
178 }
179}
180
181impl Default for Duration {
182 fn default() -> Self {
183 Duration::ZERO
184 }
185}
186
187impl Debug for Duration {
188 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189 <Duration as Display>::fmt(self, f)
190 }
191}
192
193impl Display for Duration {
194 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195 if self.nanos % NANOS_IN_HOURS == 0 {
196 write!(f, "{}h", self.nanos / NANOS_IN_HOURS)
197 } else if self.nanos % NANOS_IN_MINS == 0 {
198 write!(f, "{}min", self.nanos / NANOS_IN_MINS)
199 } else if self.nanos % NANOS_IN_SECS == 0 {
200 write!(f, "{}s", self.nanos / NANOS_IN_SECS)
201 } else if self.nanos % NANOS_IN_MILLIS == 0 {
202 write!(f, "{}ms", self.nanos / NANOS_IN_MILLIS)
203 } else {
204 write!(f, "{}ns", self.nanos)
207 }
208 }
209}