1use core::{
9 convert::TryFrom,
10 fmt::{self, Debug, Display},
11 num::{NonZeroU64, TryFromIntError},
12 ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Range, Rem, RemAssign, Sub, SubAssign},
13 str::FromStr,
14 time::Duration,
15};
16
17#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
20#[repr(transparent)]
21pub struct TimeSpan {
22 nanos: u64,
23}
24
25impl TimeSpan {
26 fn fmt(self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 if self == Self::ZERO {
28 f.write_str("0")
29 } else {
30 let mut span = self;
31 if span >= Self::DAY {
32 let days = span / Self::DAY;
33 span %= Self::DAY;
34
35 let hours = span / Self::HOUR;
36 span %= Self::HOUR;
37
38 let minutes = span / Self::MINUTE;
39 span %= Self::MINUTE;
40
41 let seconds = span / Self::SECOND;
42 span %= Self::SECOND;
43
44 let millis = span / Self::MILLISECOND;
45
46 if millis > 0 {
47 write!(f, "{days}d{hours:02}:{minutes:02}:{seconds:02}.{millis:03}")
48 } else if seconds > 0 {
49 write!(f, "{days}d{hours:02}:{minutes:02}:{seconds:02}")
50 } else {
51 write!(f, "{days}d{hours:02}:{minutes:02}")
52 }
53 } else if span >= Self::HOUR {
54 let hours = span / Self::HOUR;
55 span %= Self::HOUR;
56
57 let minutes = span / Self::MINUTE;
58 span %= Self::MINUTE;
59
60 let seconds = span / Self::SECOND;
61 span %= Self::SECOND;
62
63 let millis = span / Self::MILLISECOND;
64 if millis > 0 {
65 write!(f, "{hours}:{minutes:02}:{seconds:02}.{millis:03}")
66 } else {
67 write!(f, "{hours}:{minutes:02}:{seconds:02}")
68 }
69 } else if span >= Self::MINUTE {
70 let minutes = span / Self::MINUTE;
71 span %= Self::MINUTE;
72
73 let seconds = span / Self::SECOND;
74 span %= Self::SECOND;
75
76 let millis = span / Self::MILLISECOND;
77 if millis > 0 {
78 write!(f, "{minutes}:{seconds:02}.{millis:03}")
79 } else {
80 write!(f, "{minutes}:{seconds:02}")
81 }
82 } else if span >= Self::SECOND {
83 let seconds = span / Self::SECOND;
84 span %= Self::SECOND;
85
86 let millis = span / Self::MILLISECOND;
87 if millis > 0 {
88 write!(f, "{seconds}.{millis:03}s")
89 } else {
90 write!(f, "{seconds}s")
91 }
92 } else if span >= Self::MILLISECOND {
93 let millis = span / Self::MILLISECOND;
94 span %= Self::MILLISECOND;
95
96 let micros = span / Self::MICROSECOND;
97 if micros > 0 {
98 write!(f, "{millis}.{micros:03}ms")
99 } else {
100 write!(f, "{millis}ms")
101 }
102 } else if span >= Self::MICROSECOND {
103 let micros = span / Self::MICROSECOND;
104 span %= Self::MICROSECOND;
105
106 let nanos = span / Self::NANOSECOND;
107 if nanos > 0 {
108 write!(f, "{micros}.{nanos:03}us")
109 } else {
110 write!(f, "{micros}us")
111 }
112 } else {
113 let nanos = span / Self::NANOSECOND;
114 write!(f, "{nanos}ns")
115 }
116 }
117 }
118
119 fn fmt_full(self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120 let mut span = self;
121 let days = span / Self::DAY;
122 span %= Self::DAY;
123 let hours = span / Self::HOUR;
124 span %= Self::HOUR;
125 let minutes = span / Self::MINUTE;
126 span %= Self::MINUTE;
127 let seconds = span / Self::SECOND;
128 span %= Self::SECOND;
129 let nanos = span / Self::NANOSECOND;
130
131 write!(
132 f,
133 "{days:01}d{hours:02}:{minutes:02}:{seconds:02}.{nanos:09}"
134 )
135 }
136
137 fn fmt_nanos(self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 write!(f, "{}ns", self.nanos)
139 }
140}
141
142impl Debug for TimeSpan {
143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144 if f.alternate() {
145 self.fmt_nanos(f)
146 } else {
147 (*self).fmt(f)
148 }
149 }
150}
151
152impl Display for TimeSpan {
153 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154 if f.alternate() {
155 self.fmt_full(f)
156 } else {
157 (*self).fmt(f)
158 }
159 }
160}
161
162#[derive(Debug)]
163pub enum TimeSpanParseErr {
164 NonASCII,
165 StringTooLarge { len: usize },
166 IntParseError { source: core::num::ParseIntError },
167 UnexpectedDelimiter { delim: char, pos: usize },
168 UnexpectedEndOfString,
169 UnexpectedSuffix,
170 HoursOutOfBound { hours: u64 },
171 MinutesOutOfBound { minutes: u64 },
172 SecondsOutOfBound { seconds: u64 },
173}
174
175impl fmt::Display for TimeSpanParseErr {
176 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177 match self {
178 Self::NonASCII => f.write_str("Time spans encoded in strings are always ASCII"),
179 Self::StringTooLarge { len } => {
180 write!(
181 f,
182 "Valid time span string may never exceed {MAX_TIME_SPAN_STRING} bytes. String is {len}"
183 )
184 }
185 Self::IntParseError { .. } => f.write_str("Failed to parse integer"),
186 Self::UnexpectedDelimiter { delim, pos } => {
187 write!(f, "Unexpected delimiter '{delim}' at {pos}")
188 }
189 Self::UnexpectedEndOfString => f.write_str("Unexpected end of string"),
190 Self::UnexpectedSuffix => {
191 f.write_str("Unexpected suffix. Only `s`, `ms` and `us` suffixes are supported")
192 }
193 Self::HoursOutOfBound { hours } => {
194 write!(f, "Hours must be in range 0-23 when days are specified. Value at hours position is '{hours}'")
195 }
196 Self::MinutesOutOfBound { minutes } => {
197 write!(f, "Minutes must be in range 0-59 when hours are specified. Value at minutes position is '{minutes}'")
198 }
199 Self::SecondsOutOfBound { seconds } => {
200 write!(
201 f,
202 "Seconds must be in range 0-59 when minutes are specified. Value at seconds position is '{seconds}'"
203 )
204 }
205 }
206 }
207}
208
209#[cfg(feature = "std")]
210impl std::error::Error for TimeSpanParseErr {
211 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
212 match self {
213 Self::IntParseError { source } => Some(source),
214 _ => None,
215 }
216 }
217}
218
219const MAX_TIME_SPAN_STRING: usize = 48;
220
221struct Ranges {
222 days: Option<Range<usize>>,
223 hours: Option<Range<usize>>,
224 minutes: Option<Range<usize>>,
225 seconds: Option<Range<usize>>,
226 fract: Option<Range<usize>>,
227 denom: u32,
228}
229
230impl Ranges {
231 fn parse(self, s: &str) -> Result<TimeSpan, TimeSpanParseErr> {
232 let seconds: u64 = self
233 .seconds
234 .map_or(Ok(0), |r| s[r].trim().parse())
235 .map_err(|source| TimeSpanParseErr::IntParseError { source })?;
236
237 if self.minutes.is_some() && seconds > 59 {
238 return Err(TimeSpanParseErr::SecondsOutOfBound { seconds });
239 }
240
241 let minutes: u64 = self
242 .minutes
243 .map_or(Ok(0), |r| s[r].trim().parse())
244 .map_err(|source| TimeSpanParseErr::IntParseError { source })?;
245
246 if self.hours.is_some() && minutes > 59 {
247 return Err(TimeSpanParseErr::MinutesOutOfBound { minutes });
248 }
249
250 let hours: u64 = self
251 .hours
252 .map_or(Ok(0), |r| s[r].trim().parse())
253 .map_err(|source| TimeSpanParseErr::IntParseError { source })?;
254
255 if self.days.is_some() && hours > 23 {
256 return Err(TimeSpanParseErr::HoursOutOfBound { hours });
257 }
258
259 let days: u64 = self
260 .days
261 .map_or(Ok(0), |r| s[r].trim().parse())
262 .map_err(|source| TimeSpanParseErr::IntParseError { source })?;
263
264 let fract: u64 = self
265 .fract
266 .map_or(Ok(0), |r| s[r].trim().parse())
267 .map_err(|source| TimeSpanParseErr::IntParseError { source })?;
268
269 let nanos = if self.denom > 9 {
270 fract / 10u64.pow(self.denom - 9)
271 } else {
272 fract * 10u64.pow(9 - self.denom)
273 };
274
275 Ok(days * TimeSpan::DAY
276 + hours * TimeSpan::HOUR
277 + minutes * TimeSpan::MINUTE
278 + seconds * TimeSpan::SECOND
279 + nanos * TimeSpan::NANOSECOND)
280 }
281}
282
283impl FromStr for TimeSpan {
284 type Err = TimeSpanParseErr;
285
286 #[allow(clippy::too_many_lines)]
287 fn from_str(s: &str) -> Result<Self, Self::Err> {
288 #![allow(clippy::cast_possible_truncation)]
289
290 if !s.is_ascii() {
291 return Err(TimeSpanParseErr::NonASCII);
292 }
293
294 if s.len() > MAX_TIME_SPAN_STRING {
295 return Err(TimeSpanParseErr::StringTooLarge { len: s.len() });
296 }
297
298 let mut seps = s.match_indices(|c: char| !c.is_ascii_digit() && !c.is_ascii_whitespace());
299
300 match seps.next() {
301 Some((dh, "d" | "D" | "t" | "T")) => match seps.next() {
302 Some((hm, ":")) => match seps.next() {
303 None => Ranges {
304 days: Some(0..dh),
305 hours: Some(dh + 1..hm),
306 minutes: Some(hm + 1..s.len()),
307 seconds: None,
308 fract: None,
309 denom: 0,
310 },
311 Some((ms, ":")) => match seps.next() {
312 None => Ranges {
313 days: Some(0..dh),
314 hours: Some(dh + 1..hm),
315 minutes: Some(hm + 1..ms),
316 seconds: Some(ms + 1..s.len()),
317 fract: None,
318 denom: 0,
319 },
320 Some((sf, ".")) => {
321 if let Some((pos, delim)) = seps.next() {
322 return Err(TimeSpanParseErr::UnexpectedDelimiter {
323 delim: delim.chars().next().unwrap(),
324 pos,
325 });
326 }
327 Ranges {
328 days: Some(0..dh),
329 hours: Some(dh + 1..hm),
330 minutes: Some(hm + 1..ms),
331 seconds: Some(ms + 1..sf),
332 fract: Some(sf + 1..s.len().min(sf + 21)),
333 denom: (s.len() - sf - 1).min(20) as u32,
334 }
335 }
336
337 Some((pos, delim)) => {
338 return Err(TimeSpanParseErr::UnexpectedDelimiter {
339 delim: delim.chars().next().unwrap(),
340 pos,
341 });
342 }
343 },
344 Some((pos, delim)) => {
345 return Err(TimeSpanParseErr::UnexpectedDelimiter {
346 delim: delim.chars().next().unwrap(),
347 pos,
348 });
349 }
350 },
351 Some((pos, delim)) => {
352 return Err(TimeSpanParseErr::UnexpectedDelimiter {
353 delim: delim.chars().next().unwrap(),
354 pos,
355 });
356 }
357 None => {
358 return Err(TimeSpanParseErr::UnexpectedEndOfString);
359 }
360 },
361 Some((hms, ":")) => match seps.next() {
362 Some((ms, ":")) => match seps.next() {
363 Some((sf, ".")) => {
364 if let Some((pos, delim)) = seps.next() {
365 return Err(TimeSpanParseErr::UnexpectedDelimiter {
366 delim: delim.chars().next().unwrap(),
367 pos,
368 });
369 }
370 Ranges {
371 days: None,
372 hours: Some(0..hms),
373 minutes: Some(hms + 1..ms),
374 seconds: Some(ms + 1..sf),
375 fract: Some(sf + 1..s.len().min(sf + 21)),
376 denom: (s.len() - sf - 1).min(20) as u32,
377 }
378 }
379 None => Ranges {
380 days: None,
381 hours: Some(0..hms),
382 minutes: Some(hms + 1..ms),
383 seconds: Some(ms + 1..s.len()),
384 fract: None,
385 denom: 0,
386 },
387 Some((pos, delim)) => {
388 return Err(TimeSpanParseErr::UnexpectedDelimiter {
389 delim: delim.chars().next().unwrap(),
390 pos,
391 });
392 }
393 },
394 Some((sf, ".")) => {
395 if let Some((pos, delim)) = seps.next() {
396 return Err(TimeSpanParseErr::UnexpectedDelimiter {
397 delim: delim.chars().next().unwrap(),
398 pos,
399 });
400 }
401 Ranges {
402 days: None,
403 hours: None,
404 minutes: Some(0..hms),
405 seconds: Some(hms + 1..sf),
406 fract: Some(sf + 1..s.len()),
407 denom: (s.len() - sf - 1).min(20) as u32,
408 }
409 }
410 None => Ranges {
411 days: None,
412 hours: None,
413 minutes: Some(0..hms),
414 seconds: Some(hms + 1..s.len()),
415 fract: None,
416 denom: 0,
417 },
418 Some((pos, delim)) => {
419 return Err(TimeSpanParseErr::UnexpectedDelimiter {
420 delim: delim.chars().next().unwrap(),
421 pos,
422 });
423 }
424 },
425
426 Some((sf, ".")) => {
427 if let Some((pos, delim)) = seps.next() {
428 return Err(TimeSpanParseErr::UnexpectedDelimiter {
429 delim: delim.chars().next().unwrap(),
430 pos,
431 });
432 }
433 Ranges {
434 days: None,
435 hours: None,
436 minutes: None,
437 seconds: Some(0..sf),
438 fract: Some(sf + 1..s.len()),
439 denom: (s.len() - sf - 1).min(20) as u32,
440 }
441 }
442
443 Some((suffix, "s")) => {
444 if s[suffix..].trim() != "s" {
445 return Err(TimeSpanParseErr::UnexpectedSuffix);
446 }
447
448 let seconds: u64 = s[..suffix]
449 .trim()
450 .parse()
451 .map_err(|source| TimeSpanParseErr::IntParseError { source })?;
452 return Ok(seconds * Self::SECOND);
453 }
454
455 Some((suffix, "m")) => {
456 if s[suffix..].trim() != "ms" {
457 return Err(TimeSpanParseErr::UnexpectedSuffix);
458 }
459
460 let millis: u64 = s[..suffix]
461 .trim()
462 .parse()
463 .map_err(|source| TimeSpanParseErr::IntParseError { source })?;
464 return Ok(millis * Self::MILLISECOND);
465 }
466
467 Some((suffix, "u")) => {
468 if s[suffix..].trim() != "us" {
469 return Err(TimeSpanParseErr::UnexpectedSuffix);
470 }
471
472 let micros: u64 = s[..suffix]
473 .trim()
474 .parse()
475 .map_err(|source| TimeSpanParseErr::IntParseError { source })?;
476 return Ok(micros * Self::MICROSECOND);
477 }
478
479 None => {
480 let seconds: u64 = s
481 .trim()
482 .parse()
483 .map_err(|source| TimeSpanParseErr::IntParseError { source })?;
484 return Ok(seconds * Self::SECOND);
485 }
486
487 Some((pos, delim)) => {
488 return Err(TimeSpanParseErr::UnexpectedDelimiter {
489 delim: delim.chars().next().unwrap(),
490 pos,
491 });
492 }
493 }
494 .parse(s)
495 }
496}
497
498#[cfg(feature = "serde")]
499impl serde::Serialize for TimeSpan {
500 #[inline]
501 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
502 where
503 S: serde::Serializer,
504 {
505 if serializer.is_human_readable() {
507 serializer.serialize_str(&self.to_string())
508 } else {
509 serializer.serialize_u64(self.nanos)
510 }
511 }
512}
513
514#[cfg(feature = "serde")]
515impl<'de> serde::Deserialize<'de> for TimeSpan {
516 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
517 where
518 D: serde::Deserializer<'de>,
519 {
520 struct Visitor;
521
522 impl<'de> serde::de::Visitor<'de> for Visitor {
523 type Value = TimeSpan;
524
525 fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
526 fmt.write_str("String with encoded time span or integer representing nanoseconds")
527 }
528
529 fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> {
530 Ok(TimeSpan { nanos: v })
531 }
532
533 fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
534 where
535 E: serde::de::Error,
536 {
537 if v < 0 {
538 Err(E::custom("TimeSpan cannot be negative"))
539 } else {
540 Ok(TimeSpan { nanos: v as u64 })
541 }
542 }
543
544 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
545 where
546 E: serde::de::Error,
547 {
548 v.parse().map_err(|err| E::custom(err))
549 }
550 }
551
552 if deserializer.is_human_readable() {
553 deserializer.deserialize_str(Visitor)
554 } else {
555 deserializer.deserialize_u64(Visitor)
556 }
557 }
558}
559
560impl From<Duration> for TimeSpan {
561 #[inline]
562 fn from(duration: Duration) -> Self {
563 let nanos = duration.as_nanos();
564 let nanos = u64::try_from(nanos).expect("Duration is too large to fit in TimeSpan");
565
566 TimeSpan {
567 nanos,
568 }
569 }
570}
571
572impl From<TimeSpan> for Duration {
573 #[inline]
574 fn from(span: TimeSpan) -> Self {
575 Duration::new(span.as_seconds(), (span.as_nanos() % 1_000_000_000) as u32)
576 }
577}
578
579impl TimeSpan {
580 pub const ZERO: Self = TimeSpan { nanos: 0 };
584
585 pub const NANOSECOND: Self = TimeSpan { nanos: 1 };
588
589 pub const MICROSECOND: Self = TimeSpan { nanos: 1_000 };
591
592 pub const MILLISECOND: Self = TimeSpan { nanos: 1_000_000 };
594
595 pub const SECOND: Self = TimeSpan {
597 nanos: 1_000_000_000,
598 };
599
600 pub const MINUTE: Self = TimeSpan {
602 nanos: 60_000_000_000,
603 };
604
605 pub const HOUR: Self = TimeSpan {
607 nanos: 3_600_000_000_000,
608 };
609
610 pub const DAY: Self = TimeSpan {
612 nanos: 86_400_000_000_000,
613 };
614
615 pub const WEEK: Self = TimeSpan {
618 nanos: 604_800_000_000_000,
619 };
620
621 pub const JULIAN_YEAR: Self = TimeSpan {
625 nanos: 31_557_600_000_000_000,
626 };
627
628 pub const GREGORIAN_YEAR: Self = TimeSpan {
632 nanos: 31_556_952_000_000,
633 };
634
635 pub const SOLAR_YEAR: Self = TimeSpan {
638 nanos: 31_556_925_216_000_000,
639 };
640
641 pub const YEAR: Self = Self::SOLAR_YEAR;
644
645 #[inline]
647 #[must_use]
648 pub const fn new(nanos: u64) -> TimeSpan {
649 TimeSpan { nanos }
650 }
651
652 #[inline]
654 #[must_use]
655 pub const fn as_nanos(self) -> u64 {
656 self.nanos
657 }
658
659 #[inline]
661 #[must_use]
662 pub const fn as_micros(&self) -> u64 {
663 self.nanos / Self::MICROSECOND.nanos
664 }
665
666 #[inline]
668 #[must_use]
669 pub const fn as_millis(&self) -> u64 {
670 self.nanos / Self::MILLISECOND.nanos
671 }
672
673 #[inline]
675 #[must_use]
676 pub const fn as_seconds(&self) -> u64 {
677 self.nanos / Self::SECOND.nanos
678 }
679
680 #[inline]
682 #[must_use]
683 pub const fn as_minutes(&self) -> u64 {
684 self.nanos / Self::MINUTE.nanos
685 }
686
687 #[inline]
689 #[must_use]
690 pub const fn as_hours(&self) -> u64 {
691 self.nanos / Self::HOUR.nanos
692 }
693
694 #[inline]
696 #[must_use]
697 pub const fn as_days(&self) -> u64 {
698 self.nanos / Self::DAY.nanos
699 }
700
701 #[inline]
703 #[must_use]
704 pub const fn as_weeks(&self) -> u64 {
705 self.nanos / Self::WEEK.nanos
706 }
707
708 #[inline]
711 #[must_use]
712 pub fn as_secs_f32(&self) -> f32 {
713 #![allow(clippy::cast_precision_loss)] self.nanos as f32 / Self::SECOND.nanos as f32
716 }
717
718 #[inline]
720 #[must_use]
721 pub fn as_secs_f64(&self) -> f64 {
722 #![allow(clippy::cast_precision_loss)] self.nanos as f64 / Self::SECOND.nanos as f64
725 }
726
727 #[inline]
729 #[must_use]
730 pub const fn checked_add(self, span: TimeSpan) -> Option<TimeSpan> {
731 match self.nanos.checked_add(span.nanos) {
732 None => None,
733 Some(nanos) => Some(TimeSpan { nanos }),
734 }
735 }
736
737 #[inline]
739 #[must_use]
740 pub const fn checked_sub(self, span: TimeSpan) -> Option<TimeSpan> {
741 match self.nanos.checked_sub(span.nanos) {
742 None => None,
743 Some(nanos) => Some(TimeSpan { nanos }),
744 }
745 }
746
747 #[inline]
749 #[must_use]
750 pub const fn checked_mul(self, value: u64) -> Option<TimeSpan> {
751 match self.nanos.checked_mul(value) {
752 None => None,
753 Some(nanos) => Some(TimeSpan { nanos }),
754 }
755 }
756
757 #[inline]
759 #[must_use]
760 pub const fn checked_div(self, value: u64) -> Option<TimeSpan> {
761 match self.nanos.checked_div(value) {
762 None => None,
763 Some(nanos) => Some(TimeSpan { nanos }),
764 }
765 }
766
767 #[inline]
769 #[must_use]
770 pub const fn div(self, value: NonZeroU64) -> TimeSpan {
771 let nanos = self.nanos / value.get();
772 TimeSpan { nanos }
773 }
774
775 #[inline]
777 #[must_use]
778 pub const fn checked_div_span(self, span: TimeSpan) -> Option<u64> {
779 match self.nanos.checked_div(span.nanos) {
780 None => None,
781 Some(value) => Some(value),
782 }
783 }
784
785 #[inline]
787 #[must_use]
788 pub const fn div_span(self, span: NonZeroTimeSpan) -> u64 {
789 self.nanos / span.nanos.get()
790 }
791
792 #[inline]
794 #[must_use]
795 pub const fn checked_rem(self, value: u64) -> Option<TimeSpan> {
796 match self.nanos.checked_rem(value) {
797 None => None,
798 Some(nanos) => Some(TimeSpan { nanos }),
799 }
800 }
801
802 #[inline]
804 #[must_use]
805 pub const fn rem(self, value: NonZeroU64) -> TimeSpan {
806 let nanos = self.nanos % value.get();
807 TimeSpan { nanos }
808 }
809
810 #[inline]
812 #[must_use]
813 pub const fn checked_rem_span(self, span: TimeSpan) -> Option<TimeSpan> {
814 match self.nanos.checked_rem(span.nanos) {
815 None => None,
816 Some(nanos) => Some(TimeSpan { nanos }),
817 }
818 }
819
820 #[inline]
822 #[must_use]
823 pub const fn rem_span(self, span: NonZeroTimeSpan) -> TimeSpan {
824 let nanos = self.nanos % span.nanos.get();
825 TimeSpan { nanos }
826 }
827
828 #[inline]
830 #[must_use]
831 pub const fn hms(hours: u64, minutes: u64, seconds: u64) -> TimeSpan {
832 TimeSpan {
833 nanos: hours * Self::HOUR.nanos
834 + minutes * Self::MINUTE.nanos
835 + seconds * Self::SECOND.nanos,
836 }
837 }
838
839 #[inline]
841 #[must_use]
842 pub const fn dhms(days: u64, hours: u64, minutes: u64, seconds: u64) -> TimeSpan {
843 TimeSpan {
844 nanos: days * Self::DAY.nanos
845 + hours * Self::HOUR.nanos
846 + minutes * Self::MINUTE.nanos
847 + seconds * Self::SECOND.nanos,
848 }
849 }
850}
851
852#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
854#[repr(transparent)]
855pub struct NonZeroTimeSpan {
856 nanos: NonZeroU64,
857}
858
859impl From<NonZeroTimeSpan> for TimeSpan {
860 #[inline]
861 fn from(span: NonZeroTimeSpan) -> Self {
862 TimeSpan {
863 nanos: span.nanos.get(),
864 }
865 }
866}
867
868impl TryFrom<TimeSpan> for NonZeroTimeSpan {
869 type Error = TryFromIntError;
870
871 #[inline]
872 fn try_from(span: TimeSpan) -> Result<Self, TryFromIntError> {
873 match NonZeroU64::try_from(span.nanos) {
874 Err(err) => Err(err),
875 Ok(nanos) => Ok(NonZeroTimeSpan { nanos }),
876 }
877 }
878}
879
880impl NonZeroTimeSpan {
881 pub const NANOSECOND: Self = NonZeroTimeSpan {
884 nanos: const { NonZeroU64::new(1).unwrap() },
885 };
886
887 pub const MICROSECOND: Self = NonZeroTimeSpan {
889 nanos: const { NonZeroU64::new(1_000).unwrap() },
890 };
891
892 pub const MILLISECOND: Self = NonZeroTimeSpan {
894 nanos: const { NonZeroU64::new(1_000_000).unwrap() },
895 };
896
897 pub const SECOND: Self = NonZeroTimeSpan {
899 nanos: const { NonZeroU64::new(1_000_000_000).unwrap() },
900 };
901
902 pub const MINUTE: Self = NonZeroTimeSpan {
904 nanos: const { NonZeroU64::new(60_000_000_000).unwrap() },
905 };
906
907 pub const HOUR: Self = NonZeroTimeSpan {
909 nanos: const { NonZeroU64::new(3_600_000_000_000).unwrap() },
910 };
911
912 pub const DAY: Self = NonZeroTimeSpan {
914 nanos: const { NonZeroU64::new(86_400_000_000_000).unwrap() },
915 };
916
917 pub const WEEK: Self = NonZeroTimeSpan {
920 nanos: const { NonZeroU64::new(604_800_000_000_000).unwrap() },
921 };
922
923 pub const JULIAN_YEAR: Self = NonZeroTimeSpan {
927 nanos: const { NonZeroU64::new(31_557_600_000_000_000).unwrap() },
928 };
929
930 pub const GREGORIAN_YEAR: Self = NonZeroTimeSpan {
935 nanos: const { NonZeroU64::new(31_556_952_000_000).unwrap() },
936 };
937
938 pub const SOLAR_YEAR: Self = NonZeroTimeSpan {
941 nanos: const { NonZeroU64::new(31_556_925_216_000_000).unwrap() },
942 };
943
944 pub const YEAR: Self = Self::SOLAR_YEAR;
947
948 #[inline]
950 #[must_use]
951 pub const fn new(nanos: NonZeroU64) -> NonZeroTimeSpan {
952 NonZeroTimeSpan { nanos }
953 }
954 #[inline]
956 #[must_use]
957 pub const fn as_nanos(self) -> NonZeroU64 {
958 self.nanos
959 }
960
961 #[inline]
963 #[must_use]
964 pub const fn as_micros(&self) -> u64 {
965 self.nanos.get() / Self::MICROSECOND.nanos.get()
966 }
967
968 #[inline]
970 #[must_use]
971 pub const fn as_millis(&self) -> u64 {
972 self.nanos.get() / Self::MILLISECOND.nanos.get()
973 }
974
975 #[inline]
977 #[must_use]
978 pub const fn as_seconds(&self) -> u64 {
979 self.nanos.get() / Self::SECOND.nanos.get()
980 }
981
982 #[inline]
984 #[must_use]
985 pub const fn as_minutes(&self) -> u64 {
986 self.nanos.get() / Self::MINUTE.nanos.get()
987 }
988
989 #[inline]
991 #[must_use]
992 pub const fn as_hours(&self) -> u64 {
993 self.nanos.get() / Self::HOUR.nanos.get()
994 }
995
996 #[inline]
998 #[must_use]
999 pub const fn as_days(&self) -> u64 {
1000 self.nanos.get() / Self::DAY.nanos.get()
1001 }
1002
1003 #[inline]
1005 #[must_use]
1006 pub const fn as_weeks(&self) -> u64 {
1007 self.nanos.get() / Self::WEEK.nanos.get()
1008 }
1009
1010 #[inline]
1013 #[must_use]
1014 pub fn as_secs_f32(&self) -> f32 {
1015 #![allow(clippy::cast_precision_loss)] self.nanos.get() as f32 / Self::SECOND.nanos.get() as f32
1018 }
1019
1020 #[inline]
1022 #[must_use]
1023 pub fn as_secs_f64(&self) -> f64 {
1024 #![allow(clippy::cast_precision_loss)] self.nanos.get() as f64 / Self::SECOND.nanos.get() as f64
1027 }
1028
1029 #[inline]
1031 #[must_use]
1032 pub const fn checked_add(self, span: TimeSpan) -> Option<NonZeroTimeSpan> {
1033 match self.nanos.get().checked_add(span.nanos) {
1034 None => None,
1035 Some(nanos) => Some(NonZeroTimeSpan {
1036 nanos: unsafe {
1037 NonZeroU64::new_unchecked(nanos)
1040 },
1041 }),
1042 }
1043 }
1044
1045 #[inline]
1047 #[must_use]
1048 pub const fn checked_sub(self, span: TimeSpan) -> Option<TimeSpan> {
1049 match self.nanos.get().checked_sub(span.nanos) {
1050 None => None,
1051 Some(nanos) => Some(TimeSpan { nanos }),
1052 }
1053 }
1054
1055 #[inline]
1057 #[must_use]
1058 pub const fn checked_mul(self, value: u64) -> Option<TimeSpan> {
1059 match self.nanos.get().checked_mul(value) {
1060 None => None,
1061 Some(nanos) => Some(TimeSpan { nanos }),
1062 }
1063 }
1064
1065 #[inline]
1067 #[must_use]
1068 pub const fn checked_mul_non_zero(self, value: NonZeroU64) -> Option<NonZeroTimeSpan> {
1069 match self.nanos.get().checked_mul(value.get()) {
1070 None => None,
1071 Some(nanos) => Some(NonZeroTimeSpan {
1072 nanos: unsafe {
1073 NonZeroU64::new_unchecked(nanos)
1076 },
1077 }),
1078 }
1079 }
1080
1081 #[inline]
1083 #[must_use]
1084 pub const fn checked_div(self, value: u64) -> Option<TimeSpan> {
1085 match self.nanos.get().checked_div(value) {
1086 None => None,
1087 Some(nanos) => Some(TimeSpan { nanos }),
1088 }
1089 }
1090
1091 #[inline]
1093 #[must_use]
1094 pub const fn div(self, value: NonZeroU64) -> TimeSpan {
1095 let nanos = self.nanos.get() / value.get();
1096 TimeSpan { nanos }
1097 }
1098
1099 #[inline]
1101 #[must_use]
1102 pub const fn checked_div_span(self, span: TimeSpan) -> Option<u64> {
1103 match self.nanos.get().checked_div(span.nanos) {
1104 None => None,
1105 Some(value) => Some(value),
1106 }
1107 }
1108
1109 #[inline]
1111 #[must_use]
1112 pub const fn div_span(self, span: NonZeroTimeSpan) -> u64 {
1113 self.nanos.get() / span.nanos.get()
1114 }
1115
1116 #[inline]
1118 #[must_use]
1119 pub const fn checked_rem(self, value: u64) -> Option<TimeSpan> {
1120 match self.nanos.get().checked_rem(value) {
1121 None => None,
1122 Some(nanos) => Some(TimeSpan { nanos }),
1123 }
1124 }
1125
1126 #[inline]
1128 #[must_use]
1129 pub const fn rem(self, value: NonZeroU64) -> TimeSpan {
1130 let nanos = self.nanos.get() % value.get();
1131 TimeSpan { nanos }
1132 }
1133
1134 #[inline]
1136 #[must_use]
1137 pub const fn checked_rem_span(self, span: TimeSpan) -> Option<TimeSpan> {
1138 match self.nanos.get().checked_rem(span.nanos) {
1139 None => None,
1140 Some(nanos) => Some(TimeSpan { nanos }),
1141 }
1142 }
1143
1144 #[inline]
1146 #[must_use]
1147 pub const fn rem_span(self, span: NonZeroTimeSpan) -> TimeSpan {
1148 let nanos = self.nanos.get() % span.nanos.get();
1149 TimeSpan { nanos }
1150 }
1151}
1152
1153impl Add<TimeSpan> for TimeSpan {
1154 type Output = Self;
1155
1156 #[inline]
1157 fn add(self, rhs: TimeSpan) -> Self {
1158 self.checked_add(rhs).expect("overflow when adding spans")
1159 }
1160}
1161
1162impl Add<TimeSpan> for NonZeroTimeSpan {
1163 type Output = Self;
1164
1165 #[inline]
1166 fn add(self, rhs: TimeSpan) -> Self {
1167 self.checked_add(rhs).expect("overflow when adding spans")
1168 }
1169}
1170
1171impl Add<NonZeroTimeSpan> for TimeSpan {
1172 type Output = NonZeroTimeSpan;
1173
1174 #[inline]
1175 fn add(self, rhs: NonZeroTimeSpan) -> NonZeroTimeSpan {
1176 rhs.checked_add(self).expect("overflow when adding spans")
1177 }
1178}
1179
1180impl Add<NonZeroTimeSpan> for NonZeroTimeSpan {
1181 type Output = NonZeroTimeSpan;
1182
1183 #[inline]
1184 fn add(self, rhs: NonZeroTimeSpan) -> Self {
1185 self.checked_add(rhs.into())
1186 .expect("overflow when adding spans")
1187 }
1188}
1189
1190impl AddAssign<TimeSpan> for TimeSpan {
1191 fn add_assign(&mut self, rhs: TimeSpan) {
1192 *self = *self + rhs;
1193 }
1194}
1195
1196impl AddAssign<NonZeroTimeSpan> for TimeSpan {
1197 fn add_assign(&mut self, rhs: NonZeroTimeSpan) {
1198 *self = (*self + rhs).into();
1199 }
1200}
1201
1202impl AddAssign<TimeSpan> for NonZeroTimeSpan {
1203 fn add_assign(&mut self, rhs: TimeSpan) {
1204 *self = *self + rhs;
1205 }
1206}
1207
1208impl AddAssign<NonZeroTimeSpan> for NonZeroTimeSpan {
1209 fn add_assign(&mut self, rhs: Self) {
1210 *self = *self + rhs;
1211 }
1212}
1213
1214impl Sub<TimeSpan> for TimeSpan {
1215 type Output = TimeSpan;
1216
1217 #[inline]
1218 fn sub(self, rhs: TimeSpan) -> Self {
1219 self.checked_sub(rhs)
1220 .expect("overflow when subtracting spans")
1221 }
1222}
1223
1224impl Sub<TimeSpan> for NonZeroTimeSpan {
1225 type Output = TimeSpan;
1226
1227 #[inline]
1228 fn sub(self, rhs: TimeSpan) -> TimeSpan {
1229 self.checked_sub(rhs)
1230 .expect("overflow when subtracting spans")
1231 }
1232}
1233
1234impl Sub<NonZeroTimeSpan> for TimeSpan {
1235 type Output = TimeSpan;
1236
1237 #[inline]
1238 fn sub(self, rhs: NonZeroTimeSpan) -> TimeSpan {
1239 rhs.checked_sub(self)
1240 .expect("overflow when subtracting spans")
1241 }
1242}
1243
1244impl Sub<NonZeroTimeSpan> for NonZeroTimeSpan {
1245 type Output = TimeSpan;
1246
1247 #[inline]
1248 fn sub(self, rhs: NonZeroTimeSpan) -> TimeSpan {
1249 self.checked_sub(rhs.into())
1250 .expect("overflow when subtracting spans")
1251 }
1252}
1253
1254impl SubAssign<TimeSpan> for TimeSpan {
1255 fn sub_assign(&mut self, rhs: TimeSpan) {
1256 *self = *self - rhs;
1257 }
1258}
1259
1260impl SubAssign<NonZeroTimeSpan> for TimeSpan {
1261 fn sub_assign(&mut self, rhs: NonZeroTimeSpan) {
1262 *self = *self - rhs;
1263 }
1264}
1265
1266impl Div<TimeSpan> for TimeSpan {
1267 type Output = u64;
1268
1269 #[inline]
1270 fn div(self, rhs: TimeSpan) -> u64 {
1271 self.checked_div_span(rhs)
1272 .expect("divide by zero error when dividing span by span")
1273 }
1274}
1275
1276impl Div<NonZeroTimeSpan> for TimeSpan {
1277 type Output = u64;
1278
1279 #[inline]
1280 fn div(self, rhs: NonZeroTimeSpan) -> u64 {
1281 self.div_span(rhs)
1282 }
1283}
1284
1285impl Div<TimeSpan> for NonZeroTimeSpan {
1286 type Output = u64;
1287
1288 #[inline]
1289 fn div(self, rhs: TimeSpan) -> u64 {
1290 self.checked_div_span(rhs)
1291 .expect("divide by zero error when dividing span by span")
1292 }
1293}
1294
1295impl Div<NonZeroTimeSpan> for NonZeroTimeSpan {
1296 type Output = u64;
1297
1298 #[inline]
1299 fn div(self, rhs: NonZeroTimeSpan) -> u64 {
1300 self.div_span(rhs)
1301 }
1302}
1303
1304impl Rem<TimeSpan> for TimeSpan {
1305 type Output = TimeSpan;
1306
1307 #[inline]
1308 fn rem(self, rhs: TimeSpan) -> TimeSpan {
1309 self.checked_rem_span(rhs)
1310 .expect("divide by zero error when dividing span by span")
1311 }
1312}
1313
1314impl RemAssign<TimeSpan> for TimeSpan {
1315 #[inline]
1316 fn rem_assign(&mut self, rhs: TimeSpan) {
1317 *self = *self % rhs;
1318 }
1319}
1320
1321impl Rem<NonZeroTimeSpan> for TimeSpan {
1322 type Output = TimeSpan;
1323
1324 #[inline]
1325 fn rem(self, rhs: NonZeroTimeSpan) -> TimeSpan {
1326 self.rem_span(rhs)
1327 }
1328}
1329
1330impl RemAssign<NonZeroTimeSpan> for TimeSpan {
1331 #[inline]
1332 fn rem_assign(&mut self, rhs: NonZeroTimeSpan) {
1333 *self = *self % rhs;
1334 }
1335}
1336
1337impl Rem<TimeSpan> for NonZeroTimeSpan {
1338 type Output = TimeSpan;
1339
1340 #[inline]
1341 fn rem(self, rhs: TimeSpan) -> TimeSpan {
1342 self.checked_rem_span(rhs)
1343 .expect("divide by zero error when dividing span by span")
1344 }
1345}
1346
1347impl Rem<NonZeroTimeSpan> for NonZeroTimeSpan {
1348 type Output = TimeSpan;
1349
1350 #[inline]
1351 fn rem(self, rhs: NonZeroTimeSpan) -> TimeSpan {
1352 self.rem_span(rhs)
1353 }
1354}
1355
1356impl Mul<u64> for TimeSpan {
1357 type Output = Self;
1358
1359 #[inline]
1360 fn mul(self, rhs: u64) -> Self {
1361 self.checked_mul(rhs)
1362 .expect("overflow when multiplying span by scalar")
1363 }
1364}
1365
1366impl Mul<TimeSpan> for u64 {
1367 type Output = TimeSpan;
1368
1369 #[inline]
1370 fn mul(self, rhs: TimeSpan) -> TimeSpan {
1371 rhs * self
1372 }
1373}
1374
1375impl MulAssign<u64> for TimeSpan {
1376 #[inline]
1377 fn mul_assign(&mut self, rhs: u64) {
1378 *self = *self * rhs;
1379 }
1380}
1381
1382impl Div<u64> for TimeSpan {
1383 type Output = TimeSpan;
1384
1385 #[inline]
1386 fn div(self, rhs: u64) -> Self {
1387 self.checked_div(rhs)
1388 .expect("divide by zero error when dividing span by scalar")
1389 }
1390}
1391
1392impl DivAssign<u64> for TimeSpan {
1393 #[inline]
1394 fn div_assign(&mut self, rhs: u64) {
1395 *self = *self / rhs;
1396 }
1397}
1398
1399impl Rem<u64> for TimeSpan {
1400 type Output = TimeSpan;
1401
1402 #[inline]
1403 fn rem(self, rhs: u64) -> Self {
1404 self.checked_rem(rhs)
1405 .expect("divide by zero error when dividing span by scalar")
1406 }
1407}
1408
1409impl RemAssign<u64> for TimeSpan {
1410 #[inline]
1411 fn rem_assign(&mut self, rhs: u64) {
1412 *self = *self % rhs;
1413 }
1414}
1415
1416impl Mul<u64> for NonZeroTimeSpan {
1417 type Output = TimeSpan;
1418
1419 #[inline]
1420 fn mul(self, rhs: u64) -> TimeSpan {
1421 self.checked_mul(rhs)
1422 .expect("overflow when multiplying span by scalar")
1423 }
1424}
1425
1426impl Mul<NonZeroTimeSpan> for u64 {
1427 type Output = TimeSpan;
1428
1429 #[inline]
1430 fn mul(self, rhs: NonZeroTimeSpan) -> TimeSpan {
1431 rhs * self
1432 }
1433}
1434
1435impl Div<u64> for NonZeroTimeSpan {
1436 type Output = TimeSpan;
1437
1438 #[inline]
1439 fn div(self, rhs: u64) -> TimeSpan {
1440 self.checked_div(rhs)
1441 .expect("divide by zero error when dividing span by scalar")
1442 }
1443}
1444
1445impl Rem<u64> for NonZeroTimeSpan {
1446 type Output = TimeSpan;
1447
1448 #[inline]
1449 fn rem(self, rhs: u64) -> TimeSpan {
1450 self.checked_rem(rhs)
1451 .expect("divide by zero error when dividing span by scalar")
1452 }
1453}
1454
1455impl Mul<NonZeroU64> for TimeSpan {
1456 type Output = Self;
1457
1458 #[inline]
1459 fn mul(self, rhs: NonZeroU64) -> Self {
1460 self.checked_mul(rhs.get())
1461 .expect("overflow when multiplying span by scalar")
1462 }
1463}
1464
1465impl Mul<TimeSpan> for NonZeroU64 {
1466 type Output = TimeSpan;
1467
1468 #[inline]
1469 fn mul(self, rhs: TimeSpan) -> TimeSpan {
1470 rhs * self
1471 }
1472}
1473
1474impl MulAssign<NonZeroU64> for TimeSpan {
1475 #[inline]
1476 fn mul_assign(&mut self, rhs: NonZeroU64) {
1477 *self = *self * rhs;
1478 }
1479}
1480
1481impl Div<NonZeroU64> for TimeSpan {
1482 type Output = TimeSpan;
1483
1484 #[inline]
1485 fn div(self, rhs: NonZeroU64) -> Self {
1486 self.div(rhs)
1487 }
1488}
1489
1490impl DivAssign<NonZeroU64> for TimeSpan {
1491 #[inline]
1492 fn div_assign(&mut self, rhs: NonZeroU64) {
1493 *self = *self / rhs;
1494 }
1495}
1496
1497impl Rem<NonZeroU64> for TimeSpan {
1498 type Output = TimeSpan;
1499
1500 #[inline]
1501 fn rem(self, rhs: NonZeroU64) -> Self {
1502 self.rem(rhs)
1503 }
1504}
1505
1506impl RemAssign<NonZeroU64> for TimeSpan {
1507 #[inline]
1508 fn rem_assign(&mut self, rhs: NonZeroU64) {
1509 *self = *self % rhs;
1510 }
1511}
1512
1513impl Mul<NonZeroU64> for NonZeroTimeSpan {
1514 type Output = NonZeroTimeSpan;
1515
1516 #[inline]
1517 fn mul(self, rhs: NonZeroU64) -> NonZeroTimeSpan {
1518 self.checked_mul_non_zero(rhs)
1519 .expect("overflow when multiplying span by scalar")
1520 }
1521}
1522
1523impl Mul<NonZeroTimeSpan> for NonZeroU64 {
1524 type Output = NonZeroTimeSpan;
1525
1526 #[inline]
1527 fn mul(self, rhs: NonZeroTimeSpan) -> NonZeroTimeSpan {
1528 rhs * self
1529 }
1530}
1531
1532impl Div<NonZeroU64> for NonZeroTimeSpan {
1533 type Output = TimeSpan;
1534
1535 #[inline]
1536 fn div(self, rhs: NonZeroU64) -> TimeSpan {
1537 self.div(rhs)
1538 }
1539}
1540
1541impl Rem<NonZeroU64> for NonZeroTimeSpan {
1542 type Output = TimeSpan;
1543
1544 #[inline]
1545 fn rem(self, rhs: NonZeroU64) -> TimeSpan {
1546 self.rem(rhs)
1547 }
1548}
1549
1550pub trait TimeSpanNumExt {
1552 fn nanoseconds(self) -> TimeSpan;
1554
1555 fn microseconds(self) -> TimeSpan;
1557
1558 fn milliseconds(self) -> TimeSpan;
1560
1561 fn seconds(self) -> TimeSpan;
1563
1564 fn minutes(self) -> TimeSpan;
1566
1567 fn hours(self) -> TimeSpan;
1569
1570 fn days(self) -> TimeSpan;
1572}
1573
1574pub trait NonZeroTimeSpanNumExt {
1576 fn nanoseconds(self) -> NonZeroTimeSpan;
1578
1579 fn microseconds(self) -> NonZeroTimeSpan;
1581
1582 fn milliseconds(self) -> NonZeroTimeSpan;
1584
1585 fn seconds(self) -> NonZeroTimeSpan;
1587
1588 fn minutes(self) -> NonZeroTimeSpan;
1590
1591 fn hours(self) -> NonZeroTimeSpan;
1593
1594 fn days(self) -> NonZeroTimeSpan;
1596}
1597
1598macro_rules! impl_for_int {
1599 ($($int:ty)*) => {
1600 $(
1601 impl_for_int!(@ $int);
1602 )*
1603 };
1604
1605 (@ $int:ty) => {
1606 impl TimeSpanNumExt for $int {
1607 #[inline]
1608 fn nanoseconds(self) -> TimeSpan {
1609 TimeSpan::NANOSECOND * u64::from(self)
1610 }
1611 #[inline]
1612 fn microseconds(self) -> TimeSpan {
1613 TimeSpan::MICROSECOND * u64::from(self)
1614 }
1615 #[inline]
1616 fn milliseconds(self) -> TimeSpan {
1617 TimeSpan::MILLISECOND * u64::from(self)
1618 }
1619 #[inline]
1620 fn seconds(self) -> TimeSpan {
1621 TimeSpan::SECOND * u64::from(self)
1622 }
1623 #[inline]
1624 fn minutes(self) -> TimeSpan {
1625 TimeSpan::MINUTE * u64::from(self)
1626 }
1627 #[inline]
1628 fn hours(self) -> TimeSpan {
1629 TimeSpan::HOUR * u64::from(self)
1630 }
1631 #[inline]
1632 fn days(self) -> TimeSpan {
1633 TimeSpan::DAY * u64::from(self)
1634 }
1635 }
1636 };
1637}
1638
1639impl_for_int!(u64);
1640
1641macro_rules! impl_for_nonzero_int {
1642($($int:ty)*) => {
1643 $(
1644 impl_for_nonzero_int!(@ $int);
1645 )*
1646 };
1647
1648 (@ $int:ty) => {
1649
1650 impl NonZeroTimeSpanNumExt for $int {
1651 #[inline]
1652 fn nanoseconds(self) -> NonZeroTimeSpan {
1653 NonZeroTimeSpan::NANOSECOND * NonZeroU64::from(self)
1654 }
1655 #[inline]
1656 fn microseconds(self) -> NonZeroTimeSpan {
1657 NonZeroTimeSpan::MICROSECOND * NonZeroU64::from(self)
1658 }
1659 #[inline]
1660 fn milliseconds(self) -> NonZeroTimeSpan {
1661 NonZeroTimeSpan::MILLISECOND * NonZeroU64::from(self)
1662 }
1663 #[inline]
1664 fn seconds(self) -> NonZeroTimeSpan {
1665 NonZeroTimeSpan::SECOND * NonZeroU64::from(self)
1666 }
1667 #[inline]
1668 fn minutes(self) -> NonZeroTimeSpan {
1669 NonZeroTimeSpan::MINUTE * NonZeroU64::from(self)
1670 }
1671 #[inline]
1672 fn hours(self) -> NonZeroTimeSpan {
1673 NonZeroTimeSpan::HOUR * NonZeroU64::from(self)
1674 }
1675 #[inline]
1676 fn days(self) -> NonZeroTimeSpan {
1677 NonZeroTimeSpan::DAY * NonZeroU64::from(self)
1678 }
1679 }
1680 };
1681}
1682
1683impl_for_nonzero_int!(NonZeroU64);
1684
1685#[test]
1686fn test_span_print() {
1687 assert_eq!("1d00:00", TimeSpan::DAY.to_string());
1688 assert_eq!("1:00:00", TimeSpan::HOUR.to_string());
1689 assert_eq!("1:00", TimeSpan::MINUTE.to_string());
1690 assert_eq!("1s", TimeSpan::SECOND.to_string());
1691
1692 assert_eq!(
1693 "1:02:11",
1694 (TimeSpan::HOUR + 2 * TimeSpan::MINUTE + 11 * TimeSpan::SECOND).to_string()
1695 );
1696
1697 assert_eq!(
1698 "2:11.011",
1699 (2 * TimeSpan::MINUTE + 11 * TimeSpan::SECOND + 11 * TimeSpan::MILLISECOND).to_string()
1700 );
1701
1702 assert_eq!(
1703 "2:11.011",
1704 (2 * TimeSpan::MINUTE + 11 * TimeSpan::SECOND + 11 * TimeSpan::MILLISECOND).to_string()
1705 );
1706}
1707
1708#[test]
1709fn test_span_parse() {
1710 assert_eq!("1d00:00".parse::<TimeSpan>().unwrap(), TimeSpan::DAY);
1711 assert_eq!("1:00:00".parse::<TimeSpan>().unwrap(), TimeSpan::HOUR);
1712 assert_eq!("1:00".parse::<TimeSpan>().unwrap(), TimeSpan::MINUTE);
1713 assert_eq!("1s".parse::<TimeSpan>().unwrap(), TimeSpan::SECOND);
1714
1715 assert_eq!(
1716 "1:02:11".parse::<TimeSpan>().unwrap(),
1717 TimeSpan::HOUR + 2 * TimeSpan::MINUTE + 11 * TimeSpan::SECOND
1718 );
1719
1720 assert_eq!(
1721 "2:11.011".parse::<TimeSpan>().unwrap(),
1722 2 * TimeSpan::MINUTE + 11 * TimeSpan::SECOND + 11 * TimeSpan::MILLISECOND
1723 );
1724
1725 assert_eq!(
1726 "2:11.011".parse::<TimeSpan>().unwrap(),
1727 2 * TimeSpan::MINUTE + 11 * TimeSpan::SECOND + 11 * TimeSpan::MILLISECOND
1728 );
1729}