1use core::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign};
14use core::time::Duration;
15use core::{fmt, i64};
16#[cfg(feature = "std")]
17use std::error::Error;
18
19use crate::{expect, try_opt};
20
21#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
22use rkyv::{Archive, Deserialize, Serialize};
23
24const NANOS_PER_MICRO: i32 = 1000;
26const NANOS_PER_MILLI: i32 = 1_000_000;
28pub(crate) const NANOS_PER_SEC: i32 = 1_000_000_000;
30const MICROS_PER_SEC: i64 = 1_000_000;
32const MILLIS_PER_SEC: i64 = 1000;
34const SECS_PER_MINUTE: i64 = 60;
36const SECS_PER_HOUR: i64 = 3600;
38const SECS_PER_DAY: i64 = 86_400;
40const SECS_PER_WEEK: i64 = 604_800;
42
43#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
53#[cfg_attr(
54 any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"),
55 derive(Archive, Deserialize, Serialize),
56 archive(compare(PartialEq, PartialOrd)),
57 archive_attr(derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash))
58)]
59#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
60pub struct TimeDelta {
61 secs: i64,
62 nanos: i32, }
64
65pub(crate) const MIN: TimeDelta = TimeDelta {
67 secs: -i64::MAX / MILLIS_PER_SEC - 1,
68 nanos: NANOS_PER_SEC + (-i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI,
69};
70
71pub(crate) const MAX: TimeDelta = TimeDelta {
73 secs: i64::MAX / MILLIS_PER_SEC,
74 nanos: (i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI,
75};
76
77impl TimeDelta {
78 pub const fn new(secs: i64, nanos: u32) -> Option<TimeDelta> {
84 if secs < MIN.secs
85 || secs > MAX.secs
86 || nanos >= 1_000_000_000
87 || (secs == MAX.secs && nanos > MAX.nanos as u32)
88 || (secs == MIN.secs && nanos < MIN.nanos as u32)
89 {
90 return None;
91 }
92 Some(TimeDelta { secs, nanos: nanos as i32 })
93 }
94
95 #[inline]
104 #[must_use]
105 pub const fn weeks(weeks: i64) -> TimeDelta {
106 expect(TimeDelta::try_weeks(weeks), "TimeDelta::weeks out of bounds")
107 }
108
109 #[inline]
118 pub const fn try_weeks(weeks: i64) -> Option<TimeDelta> {
119 TimeDelta::try_seconds(try_opt!(weeks.checked_mul(SECS_PER_WEEK)))
120 }
121
122 #[inline]
131 #[must_use]
132 pub const fn days(days: i64) -> TimeDelta {
133 expect(TimeDelta::try_days(days), "TimeDelta::days out of bounds")
134 }
135
136 #[inline]
145 pub const fn try_days(days: i64) -> Option<TimeDelta> {
146 TimeDelta::try_seconds(try_opt!(days.checked_mul(SECS_PER_DAY)))
147 }
148
149 #[inline]
157 #[must_use]
158 pub const fn hours(hours: i64) -> TimeDelta {
159 expect(TimeDelta::try_hours(hours), "TimeDelta::hours out of bounds")
160 }
161
162 #[inline]
170 pub const fn try_hours(hours: i64) -> Option<TimeDelta> {
171 TimeDelta::try_seconds(try_opt!(hours.checked_mul(SECS_PER_HOUR)))
172 }
173
174 #[inline]
182 #[must_use]
183 pub const fn minutes(minutes: i64) -> TimeDelta {
184 expect(TimeDelta::try_minutes(minutes), "TimeDelta::minutes out of bounds")
185 }
186
187 #[inline]
195 pub const fn try_minutes(minutes: i64) -> Option<TimeDelta> {
196 TimeDelta::try_seconds(try_opt!(minutes.checked_mul(SECS_PER_MINUTE)))
197 }
198
199 #[inline]
206 #[must_use]
207 pub const fn seconds(seconds: i64) -> TimeDelta {
208 expect(TimeDelta::try_seconds(seconds), "TimeDelta::seconds out of bounds")
209 }
210
211 #[inline]
219 pub const fn try_seconds(seconds: i64) -> Option<TimeDelta> {
220 TimeDelta::new(seconds, 0)
221 }
222
223 #[inline]
230 pub const fn milliseconds(milliseconds: i64) -> TimeDelta {
231 expect(TimeDelta::try_milliseconds(milliseconds), "TimeDelta::milliseconds out of bounds")
232 }
233
234 #[inline]
241 pub const fn try_milliseconds(milliseconds: i64) -> Option<TimeDelta> {
242 if milliseconds < -i64::MAX {
245 return None;
246 }
247 let (secs, millis) = div_mod_floor_64(milliseconds, MILLIS_PER_SEC);
248 let d = TimeDelta { secs, nanos: millis as i32 * NANOS_PER_MILLI };
249 Some(d)
250 }
251
252 #[inline]
259 pub const fn microseconds(microseconds: i64) -> TimeDelta {
260 let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
261 let nanos = micros as i32 * NANOS_PER_MICRO;
262 TimeDelta { secs, nanos }
263 }
264
265 #[inline]
272 pub const fn nanoseconds(nanos: i64) -> TimeDelta {
273 let (secs, nanos) = div_mod_floor_64(nanos, NANOS_PER_SEC as i64);
274 TimeDelta { secs, nanos: nanos as i32 }
275 }
276
277 #[inline]
279 pub const fn num_weeks(&self) -> i64 {
280 self.num_days() / 7
281 }
282
283 pub const fn num_days(&self) -> i64 {
285 self.num_seconds() / SECS_PER_DAY
286 }
287
288 #[inline]
290 pub const fn num_hours(&self) -> i64 {
291 self.num_seconds() / SECS_PER_HOUR
292 }
293
294 #[inline]
296 pub const fn num_minutes(&self) -> i64 {
297 self.num_seconds() / SECS_PER_MINUTE
298 }
299
300 pub const fn num_seconds(&self) -> i64 {
302 if self.secs < 0 && self.nanos > 0 {
304 self.secs + 1
305 } else {
306 self.secs
307 }
308 }
309
310 pub const fn subsec_nanos(&self) -> i32 {
314 if self.secs < 0 && self.nanos > 0 {
315 self.nanos - NANOS_PER_SEC
316 } else {
317 self.nanos
318 }
319 }
320
321 pub const fn num_milliseconds(&self) -> i64 {
323 let secs_part = self.num_seconds() * MILLIS_PER_SEC;
327 let nanos_part = self.subsec_nanos() / NANOS_PER_MILLI;
328 secs_part + nanos_part as i64
329 }
330
331 pub const fn num_microseconds(&self) -> Option<i64> {
334 let secs_part = try_opt!(self.num_seconds().checked_mul(MICROS_PER_SEC));
335 let nanos_part = self.subsec_nanos() / NANOS_PER_MICRO;
336 secs_part.checked_add(nanos_part as i64)
337 }
338
339 pub const fn num_nanoseconds(&self) -> Option<i64> {
342 let secs_part = try_opt!(self.num_seconds().checked_mul(NANOS_PER_SEC as i64));
343 let nanos_part = self.subsec_nanos();
344 secs_part.checked_add(nanos_part as i64)
345 }
346
347 #[must_use]
349 pub const fn checked_add(&self, rhs: &TimeDelta) -> Option<TimeDelta> {
350 let mut secs = self.secs + rhs.secs;
353 let mut nanos = self.nanos + rhs.nanos;
354 if nanos >= NANOS_PER_SEC {
355 nanos -= NANOS_PER_SEC;
356 secs += 1;
357 }
358 TimeDelta::new(secs, nanos as u32)
359 }
360
361 #[must_use]
363 pub const fn checked_sub(&self, rhs: &TimeDelta) -> Option<TimeDelta> {
364 let mut secs = self.secs - rhs.secs;
367 let mut nanos = self.nanos - rhs.nanos;
368 if nanos < 0 {
369 nanos += NANOS_PER_SEC;
370 secs -= 1;
371 }
372 TimeDelta::new(secs, nanos as u32)
373 }
374
375 #[inline]
377 pub const fn abs(&self) -> TimeDelta {
378 if self.secs < 0 && self.nanos != 0 {
379 TimeDelta { secs: (self.secs + 1).abs(), nanos: NANOS_PER_SEC - self.nanos }
380 } else {
381 TimeDelta { secs: self.secs.abs(), nanos: self.nanos }
382 }
383 }
384
385 #[inline]
387 pub const fn min_value() -> TimeDelta {
388 MIN
389 }
390
391 #[inline]
393 pub const fn max_value() -> TimeDelta {
394 MAX
395 }
396
397 #[inline]
399 pub const fn zero() -> TimeDelta {
400 TimeDelta { secs: 0, nanos: 0 }
401 }
402
403 #[inline]
405 pub const fn is_zero(&self) -> bool {
406 self.secs == 0 && self.nanos == 0
407 }
408
409 pub const fn from_std(duration: Duration) -> Result<TimeDelta, OutOfRangeError> {
414 if duration.as_secs() > MAX.secs as u64 {
416 return Err(OutOfRangeError(()));
417 }
418 match TimeDelta::new(duration.as_secs() as i64, duration.subsec_nanos()) {
419 Some(d) => Ok(d),
420 None => Err(OutOfRangeError(())),
421 }
422 }
423
424 pub const fn to_std(&self) -> Result<Duration, OutOfRangeError> {
429 if self.secs < 0 {
430 return Err(OutOfRangeError(()));
431 }
432 Ok(Duration::new(self.secs as u64, self.nanos as u32))
433 }
434
435 pub(crate) const fn neg(self) -> TimeDelta {
437 let (secs_diff, nanos) = match self.nanos {
438 0 => (0, 0),
439 nanos => (1, NANOS_PER_SEC - nanos),
440 };
441 TimeDelta { secs: -self.secs - secs_diff, nanos }
442 }
443}
444
445impl Neg for TimeDelta {
446 type Output = TimeDelta;
447
448 #[inline]
449 fn neg(self) -> TimeDelta {
450 let (secs_diff, nanos) = match self.nanos {
451 0 => (0, 0),
452 nanos => (1, NANOS_PER_SEC - nanos),
453 };
454 TimeDelta { secs: -self.secs - secs_diff, nanos }
455 }
456}
457
458impl Add for TimeDelta {
459 type Output = TimeDelta;
460
461 fn add(self, rhs: TimeDelta) -> TimeDelta {
462 self.checked_add(&rhs).expect("`TimeDelta + TimeDelta` overflowed")
463 }
464}
465
466impl Sub for TimeDelta {
467 type Output = TimeDelta;
468
469 fn sub(self, rhs: TimeDelta) -> TimeDelta {
470 self.checked_sub(&rhs).expect("`TimeDelta - TimeDelta` overflowed")
471 }
472}
473
474impl AddAssign for TimeDelta {
475 fn add_assign(&mut self, rhs: TimeDelta) {
476 let new = self.checked_add(&rhs).expect("`TimeDelta + TimeDelta` overflowed");
477 *self = new;
478 }
479}
480
481impl SubAssign for TimeDelta {
482 fn sub_assign(&mut self, rhs: TimeDelta) {
483 let new = self.checked_sub(&rhs).expect("`TimeDelta - TimeDelta` overflowed");
484 *self = new;
485 }
486}
487
488impl Mul<i32> for TimeDelta {
489 type Output = TimeDelta;
490
491 fn mul(self, rhs: i32) -> TimeDelta {
492 let total_nanos = self.nanos as i64 * rhs as i64;
494 let (extra_secs, nanos) = div_mod_floor_64(total_nanos, NANOS_PER_SEC as i64);
495 let secs = self.secs * rhs as i64 + extra_secs;
496 TimeDelta { secs, nanos: nanos as i32 }
497 }
498}
499
500impl Div<i32> for TimeDelta {
501 type Output = TimeDelta;
502
503 fn div(self, rhs: i32) -> TimeDelta {
504 let mut secs = self.secs / rhs as i64;
505 let carry = self.secs - secs * rhs as i64;
506 let extra_nanos = carry * NANOS_PER_SEC as i64 / rhs as i64;
507 let mut nanos = self.nanos / rhs + extra_nanos as i32;
508 if nanos >= NANOS_PER_SEC {
509 nanos -= NANOS_PER_SEC;
510 secs += 1;
511 }
512 if nanos < 0 {
513 nanos += NANOS_PER_SEC;
514 secs -= 1;
515 }
516 TimeDelta { secs, nanos }
517 }
518}
519
520impl<'a> core::iter::Sum<&'a TimeDelta> for TimeDelta {
521 fn sum<I: Iterator<Item = &'a TimeDelta>>(iter: I) -> TimeDelta {
522 iter.fold(TimeDelta::zero(), |acc, x| acc + *x)
523 }
524}
525
526impl core::iter::Sum<TimeDelta> for TimeDelta {
527 fn sum<I: Iterator<Item = TimeDelta>>(iter: I) -> TimeDelta {
528 iter.fold(TimeDelta::zero(), |acc, x| acc + x)
529 }
530}
531
532impl fmt::Display for TimeDelta {
533 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
537 let (abs, sign) = if self.secs < 0 { (-*self, "-") } else { (*self, "") };
540
541 write!(f, "{}P", sign)?;
542 if abs.secs == 0 && abs.nanos == 0 {
544 return f.write_str("0D");
545 }
546
547 f.write_fmt(format_args!("T{}", abs.secs))?;
548
549 if abs.nanos > 0 {
550 let mut figures = 9usize;
552 let mut fraction_digits = abs.nanos;
553 loop {
554 let div = fraction_digits / 10;
555 let last_digit = fraction_digits % 10;
556 if last_digit != 0 {
557 break;
558 }
559 fraction_digits = div;
560 figures -= 1;
561 }
562 f.write_fmt(format_args!(".{:01$}", fraction_digits, figures))?;
563 }
564 f.write_str("S")?;
565 Ok(())
566 }
567}
568
569#[derive(Debug, Clone, Copy, PartialEq, Eq)]
576pub struct OutOfRangeError(());
577
578impl fmt::Display for OutOfRangeError {
579 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
580 write!(f, "Source duration value is out of range for the target type")
581 }
582}
583
584#[cfg(feature = "std")]
585impl Error for OutOfRangeError {
586 #[allow(deprecated)]
587 fn description(&self) -> &str {
588 "out of range error"
589 }
590}
591
592#[inline]
593const fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
594 (this.div_euclid(other), this.rem_euclid(other))
595}
596
597#[cfg(all(feature = "arbitrary", feature = "std"))]
598impl arbitrary::Arbitrary<'_> for TimeDelta {
599 fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result<TimeDelta> {
600 const MIN_SECS: i64 = -i64::MAX / MILLIS_PER_SEC - 1;
601 const MAX_SECS: i64 = i64::MAX / MILLIS_PER_SEC;
602
603 let secs: i64 = u.int_in_range(MIN_SECS..=MAX_SECS)?;
604 let nanos: i32 = u.int_in_range(0..=(NANOS_PER_SEC - 1))?;
605 let duration = TimeDelta { secs, nanos };
606
607 if duration < MIN || duration > MAX {
608 Err(arbitrary::Error::IncorrectFormat)
609 } else {
610 Ok(duration)
611 }
612 }
613}
614
615#[cfg(test)]
616mod tests {
617 use super::OutOfRangeError;
618 use super::{TimeDelta, MAX, MIN};
619 use crate::expect;
620 use core::time::Duration;
621
622 #[test]
623 fn test_duration() {
624 let days = |d| TimeDelta::try_days(d).unwrap();
625 let seconds = |s| TimeDelta::try_seconds(s).unwrap();
626
627 assert!(seconds(1) != TimeDelta::zero());
628 assert_eq!(seconds(1) + seconds(2), seconds(3));
629 assert_eq!(seconds(86_399) + seconds(4), days(1) + seconds(3));
630 assert_eq!(days(10) - seconds(1000), seconds(863_000));
631 assert_eq!(days(10) - seconds(1_000_000), seconds(-136_000));
632 assert_eq!(
633 days(2) + seconds(86_399) + TimeDelta::nanoseconds(1_234_567_890),
634 days(3) + TimeDelta::nanoseconds(234_567_890)
635 );
636 assert_eq!(-days(3), days(-3));
637 assert_eq!(-(days(3) + seconds(70)), days(-4) + seconds(86_400 - 70));
638
639 let mut d = TimeDelta::default();
640 d += TimeDelta::try_minutes(1).unwrap();
641 d -= seconds(30);
642 assert_eq!(d, seconds(30));
643 }
644
645 #[test]
646 fn test_duration_num_days() {
647 assert_eq!(TimeDelta::zero().num_days(), 0);
648 assert_eq!(TimeDelta::try_days(1).unwrap().num_days(), 1);
649 assert_eq!(TimeDelta::try_days(-1).unwrap().num_days(), -1);
650 assert_eq!(TimeDelta::try_seconds(86_399).unwrap().num_days(), 0);
651 assert_eq!(TimeDelta::try_seconds(86_401).unwrap().num_days(), 1);
652 assert_eq!(TimeDelta::try_seconds(-86_399).unwrap().num_days(), 0);
653 assert_eq!(TimeDelta::try_seconds(-86_401).unwrap().num_days(), -1);
654 assert_eq!(TimeDelta::try_days(i32::MAX as i64).unwrap().num_days(), i32::MAX as i64);
655 assert_eq!(TimeDelta::try_days(i32::MIN as i64).unwrap().num_days(), i32::MIN as i64);
656 }
657
658 #[test]
659 fn test_duration_num_seconds() {
660 assert_eq!(TimeDelta::zero().num_seconds(), 0);
661 assert_eq!(TimeDelta::try_seconds(1).unwrap().num_seconds(), 1);
662 assert_eq!(TimeDelta::try_seconds(-1).unwrap().num_seconds(), -1);
663 assert_eq!(TimeDelta::try_milliseconds(999).unwrap().num_seconds(), 0);
664 assert_eq!(TimeDelta::try_milliseconds(1001).unwrap().num_seconds(), 1);
665 assert_eq!(TimeDelta::try_milliseconds(-999).unwrap().num_seconds(), 0);
666 assert_eq!(TimeDelta::try_milliseconds(-1001).unwrap().num_seconds(), -1);
667 }
668
669 #[test]
670 fn test_duration_seconds_max_allowed() {
671 let duration = TimeDelta::try_seconds(i64::MAX / 1_000).unwrap();
672 assert_eq!(duration.num_seconds(), i64::MAX / 1_000);
673 assert_eq!(
674 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
675 i64::MAX as i128 / 1_000 * 1_000_000_000
676 );
677 }
678
679 #[test]
680 fn test_duration_seconds_max_overflow() {
681 assert!(TimeDelta::try_seconds(i64::MAX / 1_000 + 1).is_none());
682 }
683
684 #[test]
685 #[should_panic(expected = "TimeDelta::seconds out of bounds")]
686 fn test_duration_seconds_max_overflow_panic() {
687 let _ = TimeDelta::seconds(i64::MAX / 1_000 + 1);
688 }
689
690 #[test]
691 fn test_duration_seconds_min_allowed() {
692 let duration = TimeDelta::try_seconds(i64::MIN / 1_000).unwrap(); assert_eq!(duration.num_seconds(), i64::MIN / 1_000); assert_eq!(
695 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
696 -i64::MAX as i128 / 1_000 * 1_000_000_000
697 );
698 }
699
700 #[test]
701 fn test_duration_seconds_min_underflow() {
702 assert!(TimeDelta::try_seconds(-i64::MAX / 1_000 - 1).is_none());
703 }
704
705 #[test]
706 #[should_panic(expected = "TimeDelta::seconds out of bounds")]
707 fn test_duration_seconds_min_underflow_panic() {
708 let _ = TimeDelta::seconds(-i64::MAX / 1_000 - 1);
709 }
710
711 #[test]
712 fn test_duration_num_milliseconds() {
713 assert_eq!(TimeDelta::zero().num_milliseconds(), 0);
714 assert_eq!(TimeDelta::try_milliseconds(1).unwrap().num_milliseconds(), 1);
715 assert_eq!(TimeDelta::try_milliseconds(-1).unwrap().num_milliseconds(), -1);
716 assert_eq!(TimeDelta::microseconds(999).num_milliseconds(), 0);
717 assert_eq!(TimeDelta::microseconds(1001).num_milliseconds(), 1);
718 assert_eq!(TimeDelta::microseconds(-999).num_milliseconds(), 0);
719 assert_eq!(TimeDelta::microseconds(-1001).num_milliseconds(), -1);
720 }
721
722 #[test]
723 fn test_duration_milliseconds_max_allowed() {
724 let duration = TimeDelta::try_milliseconds(i64::MAX).unwrap();
727 assert_eq!(duration.num_milliseconds(), i64::MAX);
728 assert_eq!(
729 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
730 i64::MAX as i128 * 1_000_000
731 );
732 }
733
734 #[test]
735 fn test_duration_milliseconds_max_overflow() {
736 assert!(TimeDelta::try_milliseconds(i64::MAX)
739 .unwrap()
740 .checked_add(&TimeDelta::try_milliseconds(1).unwrap())
741 .is_none());
742 }
743
744 #[test]
745 fn test_duration_milliseconds_min_allowed() {
746 let duration = TimeDelta::try_milliseconds(-i64::MAX).unwrap();
750 assert_eq!(duration.num_milliseconds(), -i64::MAX);
751 assert_eq!(
752 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
753 -i64::MAX as i128 * 1_000_000
754 );
755 }
756
757 #[test]
758 fn test_duration_milliseconds_min_underflow() {
759 assert!(TimeDelta::try_milliseconds(-i64::MAX)
762 .unwrap()
763 .checked_sub(&TimeDelta::try_milliseconds(1).unwrap())
764 .is_none());
765 }
766
767 #[test]
768 #[should_panic(expected = "TimeDelta::milliseconds out of bounds")]
769 fn test_duration_milliseconds_min_underflow_panic() {
770 let _ = TimeDelta::milliseconds(i64::MIN); }
776
777 #[test]
778 fn test_duration_num_microseconds() {
779 assert_eq!(TimeDelta::zero().num_microseconds(), Some(0));
780 assert_eq!(TimeDelta::microseconds(1).num_microseconds(), Some(1));
781 assert_eq!(TimeDelta::microseconds(-1).num_microseconds(), Some(-1));
782 assert_eq!(TimeDelta::nanoseconds(999).num_microseconds(), Some(0));
783 assert_eq!(TimeDelta::nanoseconds(1001).num_microseconds(), Some(1));
784 assert_eq!(TimeDelta::nanoseconds(-999).num_microseconds(), Some(0));
785 assert_eq!(TimeDelta::nanoseconds(-1001).num_microseconds(), Some(-1));
786
787 const MICROS_PER_DAY: i64 = 86_400_000_000;
789 assert_eq!(
790 TimeDelta::try_days(i64::MAX / MICROS_PER_DAY).unwrap().num_microseconds(),
791 Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)
792 );
793 assert_eq!(
794 TimeDelta::try_days(-i64::MAX / MICROS_PER_DAY).unwrap().num_microseconds(),
795 Some(-i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)
796 );
797 assert_eq!(
798 TimeDelta::try_days(i64::MAX / MICROS_PER_DAY + 1).unwrap().num_microseconds(),
799 None
800 );
801 assert_eq!(
802 TimeDelta::try_days(-i64::MAX / MICROS_PER_DAY - 1).unwrap().num_microseconds(),
803 None
804 );
805 }
806 #[test]
807 fn test_duration_microseconds_max_allowed() {
808 let duration = TimeDelta::microseconds(i64::MAX);
812 assert_eq!(duration.num_microseconds(), Some(i64::MAX));
813 assert_eq!(
814 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
815 i64::MAX as i128 * 1_000
816 );
817 let duration = TimeDelta::try_milliseconds(i64::MAX).unwrap();
822 assert!(duration.num_microseconds().is_none());
823 assert_eq!(
824 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
825 i64::MAX as i128 * 1_000_000
826 );
827 }
828 #[test]
829 fn test_duration_microseconds_max_overflow() {
830 let duration = TimeDelta::microseconds(i64::MAX) + TimeDelta::microseconds(1);
833 assert!(duration.num_microseconds().is_none());
834 assert_eq!(
835 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
836 (i64::MAX as i128 + 1) * 1_000
837 );
838 assert!(TimeDelta::try_milliseconds(i64::MAX)
841 .unwrap()
842 .checked_add(&TimeDelta::microseconds(1))
843 .is_none());
844 }
845 #[test]
846 fn test_duration_microseconds_min_allowed() {
847 let duration = TimeDelta::microseconds(i64::MIN);
851 assert_eq!(duration.num_microseconds(), Some(i64::MIN));
852 assert_eq!(
853 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
854 i64::MIN as i128 * 1_000
855 );
856 let duration = TimeDelta::try_milliseconds(-i64::MAX).unwrap();
861 assert!(duration.num_microseconds().is_none());
862 assert_eq!(
863 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
864 -i64::MAX as i128 * 1_000_000
865 );
866 }
867 #[test]
868 fn test_duration_microseconds_min_underflow() {
869 let duration = TimeDelta::microseconds(i64::MIN) - TimeDelta::microseconds(1);
872 assert!(duration.num_microseconds().is_none());
873 assert_eq!(
874 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
875 (i64::MIN as i128 - 1) * 1_000
876 );
877 assert!(TimeDelta::try_milliseconds(-i64::MAX)
880 .unwrap()
881 .checked_sub(&TimeDelta::microseconds(1))
882 .is_none());
883 }
884
885 #[test]
886 fn test_duration_num_nanoseconds() {
887 assert_eq!(TimeDelta::zero().num_nanoseconds(), Some(0));
888 assert_eq!(TimeDelta::nanoseconds(1).num_nanoseconds(), Some(1));
889 assert_eq!(TimeDelta::nanoseconds(-1).num_nanoseconds(), Some(-1));
890
891 const NANOS_PER_DAY: i64 = 86_400_000_000_000;
893 assert_eq!(
894 TimeDelta::try_days(i64::MAX / NANOS_PER_DAY).unwrap().num_nanoseconds(),
895 Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)
896 );
897 assert_eq!(
898 TimeDelta::try_days(-i64::MAX / NANOS_PER_DAY).unwrap().num_nanoseconds(),
899 Some(-i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)
900 );
901 assert_eq!(
902 TimeDelta::try_days(i64::MAX / NANOS_PER_DAY + 1).unwrap().num_nanoseconds(),
903 None
904 );
905 assert_eq!(
906 TimeDelta::try_days(-i64::MAX / NANOS_PER_DAY - 1).unwrap().num_nanoseconds(),
907 None
908 );
909 }
910 #[test]
911 fn test_duration_nanoseconds_max_allowed() {
912 let duration = TimeDelta::nanoseconds(i64::MAX);
916 assert_eq!(duration.num_nanoseconds(), Some(i64::MAX));
917 assert_eq!(
918 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
919 i64::MAX as i128
920 );
921 let duration = TimeDelta::try_milliseconds(i64::MAX).unwrap();
925 assert!(duration.num_nanoseconds().is_none());
926 assert_eq!(
927 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
928 i64::MAX as i128 * 1_000_000
929 );
930 }
931
932 #[test]
933 fn test_duration_nanoseconds_max_overflow() {
934 let duration = TimeDelta::nanoseconds(i64::MAX) + TimeDelta::nanoseconds(1);
937 assert!(duration.num_nanoseconds().is_none());
938 assert_eq!(
939 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
940 i64::MAX as i128 + 1
941 );
942 assert!(TimeDelta::try_milliseconds(i64::MAX)
945 .unwrap()
946 .checked_add(&TimeDelta::nanoseconds(1))
947 .is_none());
948 }
949
950 #[test]
951 fn test_duration_nanoseconds_min_allowed() {
952 let duration = TimeDelta::nanoseconds(i64::MIN);
956 assert_eq!(duration.num_nanoseconds(), Some(i64::MIN));
957 assert_eq!(
958 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
959 i64::MIN as i128
960 );
961 let duration = TimeDelta::try_milliseconds(-i64::MAX).unwrap();
965 assert!(duration.num_nanoseconds().is_none());
966 assert_eq!(
967 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
968 -i64::MAX as i128 * 1_000_000
969 );
970 }
971
972 #[test]
973 fn test_duration_nanoseconds_min_underflow() {
974 let duration = TimeDelta::nanoseconds(i64::MIN) - TimeDelta::nanoseconds(1);
977 assert!(duration.num_nanoseconds().is_none());
978 assert_eq!(
979 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
980 i64::MIN as i128 - 1
981 );
982 assert!(TimeDelta::try_milliseconds(-i64::MAX)
985 .unwrap()
986 .checked_sub(&TimeDelta::nanoseconds(1))
987 .is_none());
988 }
989
990 #[test]
991 fn test_max() {
992 assert_eq!(
993 MAX.secs as i128 * 1_000_000_000 + MAX.nanos as i128,
994 i64::MAX as i128 * 1_000_000
995 );
996 assert_eq!(MAX, TimeDelta::try_milliseconds(i64::MAX).unwrap());
997 assert_eq!(MAX.num_milliseconds(), i64::MAX);
998 assert_eq!(MAX.num_microseconds(), None);
999 assert_eq!(MAX.num_nanoseconds(), None);
1000 }
1001
1002 #[test]
1003 fn test_min() {
1004 assert_eq!(
1005 MIN.secs as i128 * 1_000_000_000 + MIN.nanos as i128,
1006 -i64::MAX as i128 * 1_000_000
1007 );
1008 assert_eq!(MIN, TimeDelta::try_milliseconds(-i64::MAX).unwrap());
1009 assert_eq!(MIN.num_milliseconds(), -i64::MAX);
1010 assert_eq!(MIN.num_microseconds(), None);
1011 assert_eq!(MIN.num_nanoseconds(), None);
1012 }
1013
1014 #[test]
1015 fn test_duration_ord() {
1016 let milliseconds = |ms| TimeDelta::try_milliseconds(ms).unwrap();
1017
1018 assert!(milliseconds(1) < milliseconds(2));
1019 assert!(milliseconds(2) > milliseconds(1));
1020 assert!(milliseconds(-1) > milliseconds(-2));
1021 assert!(milliseconds(-2) < milliseconds(-1));
1022 assert!(milliseconds(-1) < milliseconds(1));
1023 assert!(milliseconds(1) > milliseconds(-1));
1024 assert!(milliseconds(0) < milliseconds(1));
1025 assert!(milliseconds(0) > milliseconds(-1));
1026 assert!(milliseconds(1_001) < milliseconds(1_002));
1027 assert!(milliseconds(-1_001) > milliseconds(-1_002));
1028 assert!(TimeDelta::nanoseconds(1_234_567_890) < TimeDelta::nanoseconds(1_234_567_891));
1029 assert!(TimeDelta::nanoseconds(-1_234_567_890) > TimeDelta::nanoseconds(-1_234_567_891));
1030 assert!(milliseconds(i64::MAX) > milliseconds(i64::MAX - 1));
1031 assert!(milliseconds(-i64::MAX) < milliseconds(-i64::MAX + 1));
1032 }
1033
1034 #[test]
1035 fn test_duration_checked_ops() {
1036 let milliseconds = |ms| TimeDelta::try_milliseconds(ms).unwrap();
1037
1038 assert_eq!(
1039 milliseconds(i64::MAX).checked_add(&milliseconds(0)),
1040 Some(milliseconds(i64::MAX))
1041 );
1042 assert_eq!(
1043 milliseconds(i64::MAX - 1).checked_add(&TimeDelta::microseconds(999)),
1044 Some(milliseconds(i64::MAX - 2) + TimeDelta::microseconds(1999))
1045 );
1046 assert!(milliseconds(i64::MAX).checked_add(&TimeDelta::microseconds(1000)).is_none());
1047 assert!(milliseconds(i64::MAX).checked_add(&TimeDelta::nanoseconds(1)).is_none());
1048
1049 assert_eq!(
1050 milliseconds(-i64::MAX).checked_sub(&milliseconds(0)),
1051 Some(milliseconds(-i64::MAX))
1052 );
1053 assert_eq!(
1054 milliseconds(-i64::MAX + 1).checked_sub(&TimeDelta::microseconds(999)),
1055 Some(milliseconds(-i64::MAX + 2) - TimeDelta::microseconds(1999))
1056 );
1057 assert!(milliseconds(-i64::MAX).checked_sub(&milliseconds(1)).is_none());
1058 assert!(milliseconds(-i64::MAX).checked_sub(&TimeDelta::nanoseconds(1)).is_none());
1059 }
1060
1061 #[test]
1062 fn test_duration_abs() {
1063 let milliseconds = |ms| TimeDelta::try_milliseconds(ms).unwrap();
1064
1065 assert_eq!(milliseconds(1300).abs(), milliseconds(1300));
1066 assert_eq!(milliseconds(1000).abs(), milliseconds(1000));
1067 assert_eq!(milliseconds(300).abs(), milliseconds(300));
1068 assert_eq!(milliseconds(0).abs(), milliseconds(0));
1069 assert_eq!(milliseconds(-300).abs(), milliseconds(300));
1070 assert_eq!(milliseconds(-700).abs(), milliseconds(700));
1071 assert_eq!(milliseconds(-1000).abs(), milliseconds(1000));
1072 assert_eq!(milliseconds(-1300).abs(), milliseconds(1300));
1073 assert_eq!(milliseconds(-1700).abs(), milliseconds(1700));
1074 assert_eq!(milliseconds(-i64::MAX).abs(), milliseconds(i64::MAX));
1075 }
1076
1077 #[test]
1078 #[allow(clippy::erasing_op)]
1079 fn test_duration_mul() {
1080 assert_eq!(TimeDelta::zero() * i32::MAX, TimeDelta::zero());
1081 assert_eq!(TimeDelta::zero() * i32::MIN, TimeDelta::zero());
1082 assert_eq!(TimeDelta::nanoseconds(1) * 0, TimeDelta::zero());
1083 assert_eq!(TimeDelta::nanoseconds(1) * 1, TimeDelta::nanoseconds(1));
1084 assert_eq!(TimeDelta::nanoseconds(1) * 1_000_000_000, TimeDelta::try_seconds(1).unwrap());
1085 assert_eq!(TimeDelta::nanoseconds(1) * -1_000_000_000, -TimeDelta::try_seconds(1).unwrap());
1086 assert_eq!(-TimeDelta::nanoseconds(1) * 1_000_000_000, -TimeDelta::try_seconds(1).unwrap());
1087 assert_eq!(
1088 TimeDelta::nanoseconds(30) * 333_333_333,
1089 TimeDelta::try_seconds(10).unwrap() - TimeDelta::nanoseconds(10)
1090 );
1091 assert_eq!(
1092 (TimeDelta::nanoseconds(1)
1093 + TimeDelta::try_seconds(1).unwrap()
1094 + TimeDelta::try_days(1).unwrap())
1095 * 3,
1096 TimeDelta::nanoseconds(3)
1097 + TimeDelta::try_seconds(3).unwrap()
1098 + TimeDelta::try_days(3).unwrap()
1099 );
1100 assert_eq!(
1101 TimeDelta::try_milliseconds(1500).unwrap() * -2,
1102 TimeDelta::try_seconds(-3).unwrap()
1103 );
1104 assert_eq!(
1105 TimeDelta::try_milliseconds(-1500).unwrap() * 2,
1106 TimeDelta::try_seconds(-3).unwrap()
1107 );
1108 }
1109
1110 #[test]
1111 fn test_duration_div() {
1112 assert_eq!(TimeDelta::zero() / i32::MAX, TimeDelta::zero());
1113 assert_eq!(TimeDelta::zero() / i32::MIN, TimeDelta::zero());
1114 assert_eq!(TimeDelta::nanoseconds(123_456_789) / 1, TimeDelta::nanoseconds(123_456_789));
1115 assert_eq!(TimeDelta::nanoseconds(123_456_789) / -1, -TimeDelta::nanoseconds(123_456_789));
1116 assert_eq!(-TimeDelta::nanoseconds(123_456_789) / -1, TimeDelta::nanoseconds(123_456_789));
1117 assert_eq!(-TimeDelta::nanoseconds(123_456_789) / 1, -TimeDelta::nanoseconds(123_456_789));
1118 assert_eq!(TimeDelta::try_seconds(1).unwrap() / 3, TimeDelta::nanoseconds(333_333_333));
1119 assert_eq!(TimeDelta::try_seconds(4).unwrap() / 3, TimeDelta::nanoseconds(1_333_333_333));
1120 assert_eq!(
1121 TimeDelta::try_seconds(-1).unwrap() / 2,
1122 TimeDelta::try_milliseconds(-500).unwrap()
1123 );
1124 assert_eq!(
1125 TimeDelta::try_seconds(1).unwrap() / -2,
1126 TimeDelta::try_milliseconds(-500).unwrap()
1127 );
1128 assert_eq!(
1129 TimeDelta::try_seconds(-1).unwrap() / -2,
1130 TimeDelta::try_milliseconds(500).unwrap()
1131 );
1132 assert_eq!(TimeDelta::try_seconds(-4).unwrap() / 3, TimeDelta::nanoseconds(-1_333_333_333));
1133 assert_eq!(TimeDelta::try_seconds(-4).unwrap() / -3, TimeDelta::nanoseconds(1_333_333_333));
1134 }
1135
1136 #[test]
1137 fn test_duration_sum() {
1138 let duration_list_1 = [TimeDelta::zero(), TimeDelta::try_seconds(1).unwrap()];
1139 let sum_1: TimeDelta = duration_list_1.iter().sum();
1140 assert_eq!(sum_1, TimeDelta::try_seconds(1).unwrap());
1141
1142 let duration_list_2 = [
1143 TimeDelta::zero(),
1144 TimeDelta::try_seconds(1).unwrap(),
1145 TimeDelta::try_seconds(6).unwrap(),
1146 TimeDelta::try_seconds(10).unwrap(),
1147 ];
1148 let sum_2: TimeDelta = duration_list_2.iter().sum();
1149 assert_eq!(sum_2, TimeDelta::try_seconds(17).unwrap());
1150
1151 let duration_arr = [
1152 TimeDelta::zero(),
1153 TimeDelta::try_seconds(1).unwrap(),
1154 TimeDelta::try_seconds(6).unwrap(),
1155 TimeDelta::try_seconds(10).unwrap(),
1156 ];
1157 let sum_3: TimeDelta = duration_arr.into_iter().sum();
1158 assert_eq!(sum_3, TimeDelta::try_seconds(17).unwrap());
1159 }
1160
1161 #[test]
1162 fn test_duration_fmt() {
1163 assert_eq!(TimeDelta::zero().to_string(), "P0D");
1164 assert_eq!(TimeDelta::try_days(42).unwrap().to_string(), "PT3628800S");
1165 assert_eq!(TimeDelta::try_days(-42).unwrap().to_string(), "-PT3628800S");
1166 assert_eq!(TimeDelta::try_seconds(42).unwrap().to_string(), "PT42S");
1167 assert_eq!(TimeDelta::try_milliseconds(42).unwrap().to_string(), "PT0.042S");
1168 assert_eq!(TimeDelta::microseconds(42).to_string(), "PT0.000042S");
1169 assert_eq!(TimeDelta::nanoseconds(42).to_string(), "PT0.000000042S");
1170 assert_eq!(
1171 (TimeDelta::try_days(7).unwrap() + TimeDelta::try_milliseconds(6543).unwrap())
1172 .to_string(),
1173 "PT604806.543S"
1174 );
1175 assert_eq!(TimeDelta::try_seconds(-86_401).unwrap().to_string(), "-PT86401S");
1176 assert_eq!(TimeDelta::nanoseconds(-1).to_string(), "-PT0.000000001S");
1177
1178 assert_eq!(
1180 format!(
1181 "{:30}",
1182 TimeDelta::try_days(1).unwrap() + TimeDelta::try_milliseconds(2345).unwrap()
1183 ),
1184 "PT86402.345S"
1185 );
1186 }
1187
1188 #[test]
1189 fn test_to_std() {
1190 assert_eq!(TimeDelta::try_seconds(1).unwrap().to_std(), Ok(Duration::new(1, 0)));
1191 assert_eq!(TimeDelta::try_seconds(86_401).unwrap().to_std(), Ok(Duration::new(86_401, 0)));
1192 assert_eq!(
1193 TimeDelta::try_milliseconds(123).unwrap().to_std(),
1194 Ok(Duration::new(0, 123_000_000))
1195 );
1196 assert_eq!(
1197 TimeDelta::try_milliseconds(123_765).unwrap().to_std(),
1198 Ok(Duration::new(123, 765_000_000))
1199 );
1200 assert_eq!(TimeDelta::nanoseconds(777).to_std(), Ok(Duration::new(0, 777)));
1201 assert_eq!(MAX.to_std(), Ok(Duration::new(9_223_372_036_854_775, 807_000_000)));
1202 assert_eq!(TimeDelta::try_seconds(-1).unwrap().to_std(), Err(OutOfRangeError(())));
1203 assert_eq!(TimeDelta::try_milliseconds(-1).unwrap().to_std(), Err(OutOfRangeError(())));
1204 }
1205
1206 #[test]
1207 fn test_from_std() {
1208 assert_eq!(
1209 Ok(TimeDelta::try_seconds(1).unwrap()),
1210 TimeDelta::from_std(Duration::new(1, 0))
1211 );
1212 assert_eq!(
1213 Ok(TimeDelta::try_seconds(86_401).unwrap()),
1214 TimeDelta::from_std(Duration::new(86_401, 0))
1215 );
1216 assert_eq!(
1217 Ok(TimeDelta::try_milliseconds(123).unwrap()),
1218 TimeDelta::from_std(Duration::new(0, 123_000_000))
1219 );
1220 assert_eq!(
1221 Ok(TimeDelta::try_milliseconds(123_765).unwrap()),
1222 TimeDelta::from_std(Duration::new(123, 765_000_000))
1223 );
1224 assert_eq!(Ok(TimeDelta::nanoseconds(777)), TimeDelta::from_std(Duration::new(0, 777)));
1225 assert_eq!(Ok(MAX), TimeDelta::from_std(Duration::new(9_223_372_036_854_775, 807_000_000)));
1226 assert_eq!(
1227 TimeDelta::from_std(Duration::new(9_223_372_036_854_776, 0)),
1228 Err(OutOfRangeError(()))
1229 );
1230 assert_eq!(
1231 TimeDelta::from_std(Duration::new(9_223_372_036_854_775, 807_000_001)),
1232 Err(OutOfRangeError(()))
1233 );
1234 }
1235
1236 #[test]
1237 fn test_duration_const() {
1238 const ONE_WEEK: TimeDelta = expect(TimeDelta::try_weeks(1), "");
1239 const ONE_DAY: TimeDelta = expect(TimeDelta::try_days(1), "");
1240 const ONE_HOUR: TimeDelta = expect(TimeDelta::try_hours(1), "");
1241 const ONE_MINUTE: TimeDelta = expect(TimeDelta::try_minutes(1), "");
1242 const ONE_SECOND: TimeDelta = expect(TimeDelta::try_seconds(1), "");
1243 const ONE_MILLI: TimeDelta = expect(TimeDelta::try_milliseconds(1), "");
1244 const ONE_MICRO: TimeDelta = TimeDelta::microseconds(1);
1245 const ONE_NANO: TimeDelta = TimeDelta::nanoseconds(1);
1246 let combo: TimeDelta = ONE_WEEK
1247 + ONE_DAY
1248 + ONE_HOUR
1249 + ONE_MINUTE
1250 + ONE_SECOND
1251 + ONE_MILLI
1252 + ONE_MICRO
1253 + ONE_NANO;
1254
1255 assert!(ONE_WEEK != TimeDelta::zero());
1256 assert!(ONE_DAY != TimeDelta::zero());
1257 assert!(ONE_HOUR != TimeDelta::zero());
1258 assert!(ONE_MINUTE != TimeDelta::zero());
1259 assert!(ONE_SECOND != TimeDelta::zero());
1260 assert!(ONE_MILLI != TimeDelta::zero());
1261 assert!(ONE_MICRO != TimeDelta::zero());
1262 assert!(ONE_NANO != TimeDelta::zero());
1263 assert_eq!(
1264 combo,
1265 TimeDelta::try_seconds(86400 * 7 + 86400 + 3600 + 60 + 1).unwrap()
1266 + TimeDelta::nanoseconds(1 + 1_000 + 1_000_000)
1267 );
1268 }
1269
1270 #[test]
1271 #[cfg(feature = "rkyv-validation")]
1272 fn test_rkyv_validation() {
1273 let duration = TimeDelta::try_seconds(1).unwrap();
1274 let bytes = rkyv::to_bytes::<_, 16>(&duration).unwrap();
1275 assert_eq!(rkyv::from_bytes::<TimeDelta>(&bytes).unwrap(), duration);
1276 }
1277}