1use crate::units::{FromUnits, Unit};
9use core::fmt::{Display, Formatter};
10
11#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
14#[non_exhaustive]
15pub enum DurationUnit {
16 #[default]
20 Second,
21
22 Millisecond,
24
25 Microsecond,
27
28 Nanosecond,
30
31 Minute,
33
34 Hour,
36
37 Day,
39
40 Year,
43}
44
45impl DurationUnit {
46 pub fn as_seconds(self, value: f64) -> f64 {
49 Duration::new(value, self)
50 .as_unit(DurationUnit::Second)
51 .value
52 }
53 pub fn as_millis(self, value: f64) -> f64 {
56 Duration::new(value, self)
57 .as_unit(DurationUnit::Millisecond)
58 .value
59 }
60
61 pub fn as_micros(self, value: f64) -> f64 {
64 Duration::new(value, self)
65 .as_unit(DurationUnit::Microsecond)
66 .value
67 }
68
69 pub fn as_nanos(self, value: f64) -> f64 {
72 Duration::new(value, self)
73 .as_unit(DurationUnit::Nanosecond)
74 .value
75 }
76
77 pub fn as_minutes(self, value: f64) -> f64 {
80 Duration::new(value, self)
81 .as_unit(DurationUnit::Minute)
82 .value
83 }
84
85 pub fn as_hours(self, value: f64) -> f64 {
88 Duration::new(value, self).as_unit(DurationUnit::Hour).value
89 }
90}
91
92macro_rules! from_units_duration {
93 ($type:ident) => {
94 impl crate::units::FromUnits<$type> for DurationUnit {
95 fn from(&self, value: $type, units: Self) -> $type {
96 match self {
97 DurationUnit::Nanosecond => match units {
99 DurationUnit::Nanosecond => value as $type,
101 DurationUnit::Microsecond => value * MICROS_TO_NANOS as $type,
102 DurationUnit::Millisecond => value * MILLIS_TO_NANOS as $type,
103 DurationUnit::Second => value * SEC_TO_NANOS as $type,
104 DurationUnit::Minute => value * MIN_TO_NANOS as $type,
105 DurationUnit::Hour => value * HOUR_TO_NANOS as $type,
106 DurationUnit::Day => value * DAY_TO_NANOS as $type,
107 DurationUnit::Year => value * YEAR_TO_NANOS as $type,
108 },
109 DurationUnit::Microsecond => match units {
110 DurationUnit::Nanosecond => value * NANOS_TO_MICROS as $type,
112 DurationUnit::Microsecond => value as $type,
113 DurationUnit::Millisecond => value * MILLIS_TO_MICROS as $type,
114 DurationUnit::Second => value * SEC_TO_MILLIS as $type,
115 DurationUnit::Minute => value * MIN_TO_MICROS as $type,
116 DurationUnit::Hour => value * HOUR_TO_MICROS as $type,
117 DurationUnit::Day => value * DAY_TO_MICROS as $type,
118 DurationUnit::Year => value * YEAR_TO_MICROS as $type,
119 },
120 DurationUnit::Millisecond => match units {
121 DurationUnit::Nanosecond => value * NANOS_TO_MILLIS as $type,
123 DurationUnit::Microsecond => value * MICROS_TO_MILLIS as $type,
124 DurationUnit::Millisecond => value as $type,
125 DurationUnit::Second => value * SEC_TO_MILLIS as $type,
126 DurationUnit::Minute => value * MIN_TO_MILLIS as $type,
127 DurationUnit::Hour => value * HOUR_TO_MILLIS as $type,
128 DurationUnit::Day => value * DAY_TO_MILLIS as $type,
129 DurationUnit::Year => value * YEAR_TO_MILLIS as $type,
130 },
131 DurationUnit::Second => match units {
132 DurationUnit::Nanosecond => value * NANOS_TO_SEC as $type,
134 DurationUnit::Microsecond => value * MICROS_TO_SECS as $type,
135 DurationUnit::Millisecond => value * MILLIS_TO_SEC as $type,
136 DurationUnit::Second => value as $type,
137 DurationUnit::Minute => value * MIN_TO_SEC as $type,
138 DurationUnit::Hour => value * HOUR_TO_SEC as $type,
139 DurationUnit::Day => value * DAY_TO_SEC as $type,
140 DurationUnit::Year => value * YEAR_TO_SEC as $type,
141 },
142 DurationUnit::Minute => match units {
143 DurationUnit::Nanosecond => value * NANOS_TO_MIN as $type,
145 DurationUnit::Microsecond => value * MICROS_TO_MIN as $type,
146 DurationUnit::Millisecond => value * MILLIS_TO_MIN as $type,
147 DurationUnit::Second => value * SEC_TO_MIN as $type,
148 DurationUnit::Minute => value as $type,
149 DurationUnit::Hour => value * HOUR_TO_MIN as $type,
150 DurationUnit::Day => value * DAY_TO_MIN as $type,
151 DurationUnit::Year => value * YEAR_TO_MIN as $type,
152 },
153 DurationUnit::Hour => match units {
154 DurationUnit::Nanosecond => value * NANOS_TO_HOUR as $type,
156 DurationUnit::Microsecond => value * MICROS_TO_HOUR as $type,
157 DurationUnit::Millisecond => value * MILLIS_TO_HOUR as $type,
158 DurationUnit::Second => value * SEC_TO_HOUR as $type,
159 DurationUnit::Minute => value * MIN_TO_HOUR as $type,
160 DurationUnit::Hour => value as $type,
161 DurationUnit::Day => value * DAY_TO_HOUR as $type,
162 DurationUnit::Year => value * YEAR_TO_HOUR as $type,
163 },
164 DurationUnit::Day => match units {
165 DurationUnit::Nanosecond => value * NANOS_TO_DAY as $type,
167 DurationUnit::Microsecond => value * MICROS_TO_DAY as $type,
168 DurationUnit::Millisecond => value * MILLIS_TO_DAY as $type,
169 DurationUnit::Second => value * SEC_TO_DAY as $type,
170 DurationUnit::Minute => value * MIN_TO_DAY as $type,
171 DurationUnit::Hour => value * HOUR_TO_DAY as $type,
172 DurationUnit::Day => value as $type,
173 DurationUnit::Year => value * YEAR_TO_DAY as $type,
174 },
175 DurationUnit::Year => match units {
176 DurationUnit::Nanosecond => value * NANOS_TO_YEAR as $type,
178 DurationUnit::Microsecond => value * MICROS_TO_YEAR as $type,
179 DurationUnit::Millisecond => value * MILLIS_TO_YEAR as $type,
180 DurationUnit::Second => value * SEC_TO_YEAR as $type,
181 DurationUnit::Minute => value * MIN_TO_YEAR as $type,
182 DurationUnit::Hour => value * HOUR_TO_YEAR as $type,
183 DurationUnit::Day => value * DAY_TO_YEAR as $type,
184 DurationUnit::Year => value as $type,
185 },
186 }
187 }
188 }
189 };
190}
191
192basic_unit!(Duration, DurationUnit, Second);
193from_units_duration!(u32);
194from_units_duration!(i32);
195from_units_duration!(u64);
196from_units_duration!(i64);
197from_units_duration!(f32);
198from_units_duration!(f64);
199
200impl From<core::time::Duration> for Duration {
201 fn from(value: core::time::Duration) -> Self {
202 Duration::new(value.as_secs_f64(), DurationUnit::Second)
203 }
204}
205
206impl From<Duration> for core::time::Duration {
207 fn from(value: Duration) -> Self {
208 let secs = value.as_seconds();
209 let frac_sec = value.as_seconds_f64() - secs as f64;
210 let nanos = DurationUnit::Second.as_nanos(frac_sec) as u32;
211 core::time::Duration::new(secs, nanos)
212 }
213}
214
215impl Duration {
216 pub const fn new_seconds(value: f64) -> Duration {
219 Duration {
220 value,
221 units: DurationUnit::Second,
222 }
223 }
224
225 pub fn as_ydhms(&self) -> (u64, u16, u8, u8, u8) {
228 let mut rem = *self;
229 let years = rem.as_years();
230 rem -= Duration::from_years(years);
231 let (d, h, m, s) = rem.as_dhms();
232 (years, d as u16, h, m, s)
233 }
234
235 pub fn as_dhms(&self) -> (u64, u8, u8, u8) {
238 let mut rem = *self;
239 let days = rem.as_days();
240 rem -= Duration::from_days(days);
241 let (h, m, s) = rem.as_hms();
242 (days, h as u8, m, s)
243 }
244
245 pub fn as_hms(&self) -> (u64, u8, u8) {
248 let mut rem = *self;
249 let hours = rem.as_hours();
250 rem -= Duration::from_hours(hours);
251 let minutes = rem.as_minutes();
252 rem -= Duration::from_minutes(minutes);
253 let seconds = rem.as_seconds();
254 (hours, minutes as u8, seconds as u8)
255 }
256
257 pub fn as_seconds(&self) -> u64 {
260 self.as_unit(DurationUnit::Second).value() as u64
261 }
262
263 pub fn as_seconds_f64(&self) -> f64 {
265 self.as_unit(DurationUnit::Second).value()
266 }
267
268 pub fn as_seconds_f32(&self) -> f32 {
270 self.as_unit(DurationUnit::Second).value() as f32
271 }
272
273 pub fn as_millis(&self) -> u64 {
276 self.as_unit(DurationUnit::Millisecond).value() as u64
277 }
278
279 pub fn as_micros(&self) -> u64 {
282 self.as_unit(DurationUnit::Microsecond).value() as u64
283 }
284
285 pub fn as_nanos(&self) -> u64 {
288 self.as_unit(DurationUnit::Nanosecond).value() as u64
289 }
290
291 pub fn as_minutes(&self) -> u64 {
294 self.as_unit(DurationUnit::Minute).value() as u64
295 }
296
297 pub fn as_hours(&self) -> u64 {
300 self.as_unit(DurationUnit::Hour).value() as u64
301 }
302
303 pub fn as_days(&self) -> u64 {
306 self.as_unit(DurationUnit::Day).value() as u64
307 }
308
309 pub fn as_years(&self) -> u64 {
312 self.as_unit(DurationUnit::Year).value() as u64
313 }
314}
315
316impl Duration {
318 pub const fn from_micros(micros: u64) -> Duration {
330 Duration::new(micros as f64, DurationUnit::Microsecond)
331 }
332
333 pub const fn from_millis(millis: u64) -> Duration {
345 Duration::new(millis as f64, DurationUnit::Millisecond)
346 }
347
348 pub const fn from_nanos(nanos: u64) -> Duration {
360 Duration::new(nanos as f64, DurationUnit::Nanosecond)
361 }
362
363 pub const fn from_minutes(minutes: u64) -> Duration {
375 Duration::new(minutes as f64, DurationUnit::Minute)
376 }
377
378 pub const fn from_hours(hours: u64) -> Duration {
390 Duration::new(hours as f64, DurationUnit::Hour)
391 }
392
393 pub const fn from_days(days: u64) -> Duration {
405 Duration::new(days as f64, DurationUnit::Day)
406 }
407
408 pub const fn from_years(years: u64) -> Duration {
420 Duration::new(years as f64, DurationUnit::Year)
421 }
422
423 pub const fn from_seconds(seconds: u64) -> Duration {
435 Duration::new(seconds as f64, DurationUnit::Second)
436 }
437
438 pub const fn from_seconds_f64(seconds: f64) -> Duration {
450 Duration::new(seconds, DurationUnit::Second)
451 }
452}
453
454impl Display for Duration {
455 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
456 f.write_fmt(format_args!("{} {:?}", self.value, self.units))
457 }
458}
459
460pub const NANOS_TO_MICROS: f64 = 1e-3;
462pub const MICROS_TO_MILLIS: f64 = 1e-3;
463pub const MILLIS_TO_SEC: f64 = 1e-3;
464pub const SEC_TO_MIN: f64 = 1. / MIN_TO_SEC;
465pub const MIN_TO_HOUR: f64 = 1. / HOUR_TO_MIN;
466pub const HOUR_TO_DAY: f64 = 1. / DAY_TO_HOUR;
467pub const DAY_TO_YEAR: f64 = 1. / YEAR_TO_DAY;
468
469pub const YEAR_TO_DAY: f64 = 365_f64;
471pub const DAY_TO_HOUR: f64 = 24_f64;
472pub const HOUR_TO_MIN: f64 = 60_f64;
473pub const MIN_TO_SEC: f64 = 60_f64;
474pub const SEC_TO_MILLIS: f64 = 1e3;
475pub const MILLIS_TO_MICROS: f64 = 1e3;
476pub const MICROS_TO_NANOS: f64 = 1e3;
477
478pub const YEAR_TO_HOUR: f64 = YEAR_TO_DAY * DAY_TO_HOUR;
480pub const DAY_TO_MIN: f64 = DAY_TO_HOUR * HOUR_TO_MIN;
481pub const HOUR_TO_SEC: f64 = HOUR_TO_MIN * MIN_TO_SEC;
482pub const MIN_TO_MILLIS: f64 = MIN_TO_SEC * SEC_TO_MILLIS;
483pub const SEC_TO_MICROS: f64 = SEC_TO_MILLIS * MILLIS_TO_MICROS;
484pub const MILLIS_TO_NANOS: f64 = MILLIS_TO_MICROS * MICROS_TO_NANOS;
485
486pub const NANOS_TO_MILLIS: f64 = NANOS_TO_MICROS * MICROS_TO_MILLIS;
488pub const MICROS_TO_SECS: f64 = MICROS_TO_MILLIS * MILLIS_TO_SEC;
489pub const MILLIS_TO_MIN: f64 = MILLIS_TO_SEC * SEC_TO_MIN;
490pub const SEC_TO_HOUR: f64 = SEC_TO_MIN * MIN_TO_HOUR;
491pub const MIN_TO_DAY: f64 = MIN_TO_HOUR * HOUR_TO_DAY;
492pub const HOUR_TO_YEAR: f64 = HOUR_TO_DAY * DAY_TO_YEAR;
493
494pub const YEAR_TO_MIN: f64 = YEAR_TO_HOUR * HOUR_TO_MIN;
496pub const DAY_TO_SEC: f64 = DAY_TO_MIN * MIN_TO_SEC;
497pub const HOUR_TO_MILLIS: f64 = HOUR_TO_SEC * SEC_TO_MILLIS;
498pub const MIN_TO_MICROS: f64 = MIN_TO_MILLIS * MILLIS_TO_MICROS;
499pub const SEC_TO_NANOS: f64 = SEC_TO_MICROS * MICROS_TO_NANOS;
500
501pub const NANOS_TO_SEC: f64 = NANOS_TO_MILLIS * MILLIS_TO_SEC;
503pub const MICROS_TO_MIN: f64 = MICROS_TO_SECS * SEC_TO_MIN;
504pub const MILLIS_TO_HOUR: f64 = MILLIS_TO_MIN * MIN_TO_HOUR;
505pub const SEC_TO_DAY: f64 = SEC_TO_HOUR * HOUR_TO_DAY;
506pub const MIN_TO_YEAR: f64 = MIN_TO_DAY * DAY_TO_YEAR;
507
508pub const YEAR_TO_SEC: f64 = YEAR_TO_MIN * MIN_TO_SEC;
510pub const DAY_TO_MILLIS: f64 = DAY_TO_SEC * SEC_TO_MILLIS;
511pub const HOUR_TO_MICROS: f64 = HOUR_TO_MILLIS * MILLIS_TO_MICROS;
512pub const MIN_TO_NANOS: f64 = MIN_TO_MICROS * MICROS_TO_NANOS;
513
514pub const NANOS_TO_MIN: f64 = NANOS_TO_SEC * SEC_TO_MIN;
516pub const MICROS_TO_HOUR: f64 = MICROS_TO_MIN * MIN_TO_HOUR;
517pub const MILLIS_TO_DAY: f64 = MILLIS_TO_HOUR * HOUR_TO_DAY;
518pub const SEC_TO_YEAR: f64 = SEC_TO_DAY * DAY_TO_YEAR;
519
520pub const YEAR_TO_MILLIS: f64 = YEAR_TO_SEC * SEC_TO_MILLIS;
522pub const DAY_TO_MICROS: f64 = DAY_TO_MILLIS * MILLIS_TO_MICROS;
523pub const HOUR_TO_NANOS: f64 = HOUR_TO_MICROS * MICROS_TO_NANOS;
524
525pub const NANOS_TO_HOUR: f64 = NANOS_TO_MIN * MIN_TO_HOUR;
527pub const MICROS_TO_DAY: f64 = MICROS_TO_HOUR * HOUR_TO_DAY;
528pub const MILLIS_TO_YEAR: f64 = MILLIS_TO_DAY * DAY_TO_YEAR;
529
530pub const YEAR_TO_MICROS: f64 = YEAR_TO_MILLIS * MILLIS_TO_MICROS;
532pub const DAY_TO_NANOS: f64 = DAY_TO_MICROS * MICROS_TO_NANOS;
533
534pub const NANOS_TO_DAY: f64 = NANOS_TO_HOUR * HOUR_TO_DAY;
536pub const MICROS_TO_YEAR: f64 = MICROS_TO_DAY * DAY_TO_YEAR;
537
538pub const YEAR_TO_NANOS: f64 = YEAR_TO_MICROS * MICROS_TO_NANOS;
540
541pub const NANOS_TO_YEAR: f64 = NANOS_TO_DAY * DAY_TO_YEAR;