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 core::time::Duration;
620
621 #[test]
622 fn test_duration() {
623 assert!(TimeDelta::seconds(1) != TimeDelta::zero());
624 assert_eq!(TimeDelta::seconds(1) + TimeDelta::seconds(2), TimeDelta::seconds(3));
625 assert_eq!(
626 TimeDelta::seconds(86_399) + TimeDelta::seconds(4),
627 TimeDelta::days(1) + TimeDelta::seconds(3)
628 );
629 assert_eq!(TimeDelta::days(10) - TimeDelta::seconds(1000), TimeDelta::seconds(863_000));
630 assert_eq!(
631 TimeDelta::days(10) - TimeDelta::seconds(1_000_000),
632 TimeDelta::seconds(-136_000)
633 );
634 assert_eq!(
635 TimeDelta::days(2) + TimeDelta::seconds(86_399) + TimeDelta::nanoseconds(1_234_567_890),
636 TimeDelta::days(3) + TimeDelta::nanoseconds(234_567_890)
637 );
638 assert_eq!(-TimeDelta::days(3), TimeDelta::days(-3));
639 assert_eq!(
640 -(TimeDelta::days(3) + TimeDelta::seconds(70)),
641 TimeDelta::days(-4) + TimeDelta::seconds(86_400 - 70)
642 );
643
644 let mut d = TimeDelta::default();
645 d += TimeDelta::minutes(1);
646 d -= TimeDelta::seconds(30);
647 assert_eq!(d, TimeDelta::seconds(30));
648 }
649
650 #[test]
651 fn test_duration_num_days() {
652 assert_eq!(TimeDelta::zero().num_days(), 0);
653 assert_eq!(TimeDelta::days(1).num_days(), 1);
654 assert_eq!(TimeDelta::days(-1).num_days(), -1);
655 assert_eq!(TimeDelta::seconds(86_399).num_days(), 0);
656 assert_eq!(TimeDelta::seconds(86_401).num_days(), 1);
657 assert_eq!(TimeDelta::seconds(-86_399).num_days(), 0);
658 assert_eq!(TimeDelta::seconds(-86_401).num_days(), -1);
659 assert_eq!(TimeDelta::days(i32::MAX as i64).num_days(), i32::MAX as i64);
660 assert_eq!(TimeDelta::days(i32::MIN as i64).num_days(), i32::MIN as i64);
661 }
662
663 #[test]
664 fn test_duration_num_seconds() {
665 assert_eq!(TimeDelta::zero().num_seconds(), 0);
666 assert_eq!(TimeDelta::seconds(1).num_seconds(), 1);
667 assert_eq!(TimeDelta::seconds(-1).num_seconds(), -1);
668 assert_eq!(TimeDelta::milliseconds(999).num_seconds(), 0);
669 assert_eq!(TimeDelta::milliseconds(1001).num_seconds(), 1);
670 assert_eq!(TimeDelta::milliseconds(-999).num_seconds(), 0);
671 assert_eq!(TimeDelta::milliseconds(-1001).num_seconds(), -1);
672 }
673 #[test]
674 fn test_duration_seconds_max_allowed() {
675 let duration = TimeDelta::seconds(i64::MAX / 1_000);
676 assert_eq!(duration.num_seconds(), i64::MAX / 1_000);
677 assert_eq!(
678 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
679 i64::MAX as i128 / 1_000 * 1_000_000_000
680 );
681 }
682 #[test]
683 fn test_duration_seconds_max_overflow() {
684 assert!(TimeDelta::try_seconds(i64::MAX / 1_000 + 1).is_none());
685 }
686 #[test]
687 #[should_panic(expected = "TimeDelta::seconds out of bounds")]
688 fn test_duration_seconds_max_overflow_panic() {
689 let _ = TimeDelta::seconds(i64::MAX / 1_000 + 1);
690 }
691 #[test]
692 fn test_duration_seconds_min_allowed() {
693 let duration = TimeDelta::seconds(i64::MIN / 1_000); assert_eq!(duration.num_seconds(), i64::MIN / 1_000); assert_eq!(
696 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
697 -i64::MAX as i128 / 1_000 * 1_000_000_000
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 #[test]
705 #[should_panic(expected = "TimeDelta::seconds out of bounds")]
706 fn test_duration_seconds_min_underflow_panic() {
707 let _ = TimeDelta::seconds(-i64::MAX / 1_000 - 1);
708 }
709
710 #[test]
711 fn test_duration_num_milliseconds() {
712 assert_eq!(TimeDelta::zero().num_milliseconds(), 0);
713 assert_eq!(TimeDelta::milliseconds(1).num_milliseconds(), 1);
714 assert_eq!(TimeDelta::milliseconds(-1).num_milliseconds(), -1);
715 assert_eq!(TimeDelta::microseconds(999).num_milliseconds(), 0);
716 assert_eq!(TimeDelta::microseconds(1001).num_milliseconds(), 1);
717 assert_eq!(TimeDelta::microseconds(-999).num_milliseconds(), 0);
718 assert_eq!(TimeDelta::microseconds(-1001).num_milliseconds(), -1);
719 }
720 #[test]
721 fn test_duration_milliseconds_max_allowed() {
722 let duration = TimeDelta::milliseconds(i64::MAX);
725 assert_eq!(duration.num_milliseconds(), i64::MAX);
726 assert_eq!(
727 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
728 i64::MAX as i128 * 1_000_000
729 );
730 }
731 #[test]
732 fn test_duration_milliseconds_max_overflow() {
733 assert!(TimeDelta::milliseconds(i64::MAX)
736 .checked_add(&TimeDelta::milliseconds(1))
737 .is_none());
738 }
739 #[test]
740 fn test_duration_milliseconds_min_allowed() {
741 let duration = TimeDelta::milliseconds(-i64::MAX);
745 assert_eq!(duration.num_milliseconds(), -i64::MAX);
746 assert_eq!(
747 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
748 -i64::MAX as i128 * 1_000_000
749 );
750 }
751 #[test]
752 fn test_duration_milliseconds_min_underflow() {
753 assert!(TimeDelta::milliseconds(-i64::MAX)
756 .checked_sub(&TimeDelta::milliseconds(1))
757 .is_none());
758 }
759 #[test]
760 #[should_panic(expected = "TimeDelta::milliseconds out of bounds")]
761 fn test_duration_milliseconds_min_underflow_panic() {
762 let _ = TimeDelta::milliseconds(i64::MIN); }
768
769 #[test]
770 fn test_duration_num_microseconds() {
771 assert_eq!(TimeDelta::zero().num_microseconds(), Some(0));
772 assert_eq!(TimeDelta::microseconds(1).num_microseconds(), Some(1));
773 assert_eq!(TimeDelta::microseconds(-1).num_microseconds(), Some(-1));
774 assert_eq!(TimeDelta::nanoseconds(999).num_microseconds(), Some(0));
775 assert_eq!(TimeDelta::nanoseconds(1001).num_microseconds(), Some(1));
776 assert_eq!(TimeDelta::nanoseconds(-999).num_microseconds(), Some(0));
777 assert_eq!(TimeDelta::nanoseconds(-1001).num_microseconds(), Some(-1));
778
779 const MICROS_PER_DAY: i64 = 86_400_000_000;
781 assert_eq!(
782 TimeDelta::days(i64::MAX / MICROS_PER_DAY).num_microseconds(),
783 Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)
784 );
785 assert_eq!(
786 TimeDelta::days(-i64::MAX / MICROS_PER_DAY).num_microseconds(),
787 Some(-i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)
788 );
789 assert_eq!(TimeDelta::days(i64::MAX / MICROS_PER_DAY + 1).num_microseconds(), None);
790 assert_eq!(TimeDelta::days(-i64::MAX / MICROS_PER_DAY - 1).num_microseconds(), None);
791 }
792 #[test]
793 fn test_duration_microseconds_max_allowed() {
794 let duration = TimeDelta::microseconds(i64::MAX);
798 assert_eq!(duration.num_microseconds(), Some(i64::MAX));
799 assert_eq!(
800 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
801 i64::MAX as i128 * 1_000
802 );
803 let duration = TimeDelta::milliseconds(i64::MAX);
808 assert!(duration.num_microseconds().is_none());
809 assert_eq!(
810 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
811 i64::MAX as i128 * 1_000_000
812 );
813 }
814 #[test]
815 fn test_duration_microseconds_max_overflow() {
816 let duration = TimeDelta::microseconds(i64::MAX) + TimeDelta::microseconds(1);
819 assert!(duration.num_microseconds().is_none());
820 assert_eq!(
821 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
822 (i64::MAX as i128 + 1) * 1_000
823 );
824 assert!(TimeDelta::milliseconds(i64::MAX)
827 .checked_add(&TimeDelta::microseconds(1))
828 .is_none());
829 }
830 #[test]
831 fn test_duration_microseconds_min_allowed() {
832 let duration = TimeDelta::microseconds(i64::MIN);
836 assert_eq!(duration.num_microseconds(), Some(i64::MIN));
837 assert_eq!(
838 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
839 i64::MIN as i128 * 1_000
840 );
841 let duration = TimeDelta::milliseconds(-i64::MAX);
846 assert!(duration.num_microseconds().is_none());
847 assert_eq!(
848 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
849 -i64::MAX as i128 * 1_000_000
850 );
851 }
852 #[test]
853 fn test_duration_microseconds_min_underflow() {
854 let duration = TimeDelta::microseconds(i64::MIN) - TimeDelta::microseconds(1);
857 assert!(duration.num_microseconds().is_none());
858 assert_eq!(
859 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
860 (i64::MIN as i128 - 1) * 1_000
861 );
862 assert!(TimeDelta::milliseconds(-i64::MAX)
865 .checked_sub(&TimeDelta::microseconds(1))
866 .is_none());
867 }
868
869 #[test]
870 fn test_duration_num_nanoseconds() {
871 assert_eq!(TimeDelta::zero().num_nanoseconds(), Some(0));
872 assert_eq!(TimeDelta::nanoseconds(1).num_nanoseconds(), Some(1));
873 assert_eq!(TimeDelta::nanoseconds(-1).num_nanoseconds(), Some(-1));
874
875 const NANOS_PER_DAY: i64 = 86_400_000_000_000;
877 assert_eq!(
878 TimeDelta::days(i64::MAX / NANOS_PER_DAY).num_nanoseconds(),
879 Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)
880 );
881 assert_eq!(
882 TimeDelta::days(-i64::MAX / NANOS_PER_DAY).num_nanoseconds(),
883 Some(-i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)
884 );
885 assert_eq!(TimeDelta::days(i64::MAX / NANOS_PER_DAY + 1).num_nanoseconds(), None);
886 assert_eq!(TimeDelta::days(-i64::MAX / NANOS_PER_DAY - 1).num_nanoseconds(), None);
887 }
888 #[test]
889 fn test_duration_nanoseconds_max_allowed() {
890 let duration = TimeDelta::nanoseconds(i64::MAX);
894 assert_eq!(duration.num_nanoseconds(), Some(i64::MAX));
895 assert_eq!(
896 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
897 i64::MAX as i128
898 );
899 let duration = TimeDelta::milliseconds(i64::MAX);
903 assert!(duration.num_nanoseconds().is_none());
904 assert_eq!(
905 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
906 i64::MAX as i128 * 1_000_000
907 );
908 }
909 #[test]
910 fn test_duration_nanoseconds_max_overflow() {
911 let duration = TimeDelta::nanoseconds(i64::MAX) + TimeDelta::nanoseconds(1);
914 assert!(duration.num_nanoseconds().is_none());
915 assert_eq!(
916 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
917 i64::MAX as i128 + 1
918 );
919 assert!(TimeDelta::milliseconds(i64::MAX)
922 .checked_add(&TimeDelta::nanoseconds(1))
923 .is_none());
924 }
925 #[test]
926 fn test_duration_nanoseconds_min_allowed() {
927 let duration = TimeDelta::nanoseconds(i64::MIN);
931 assert_eq!(duration.num_nanoseconds(), Some(i64::MIN));
932 assert_eq!(
933 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
934 i64::MIN as i128
935 );
936 let duration = TimeDelta::milliseconds(-i64::MAX);
940 assert!(duration.num_nanoseconds().is_none());
941 assert_eq!(
942 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
943 -i64::MAX as i128 * 1_000_000
944 );
945 }
946 #[test]
947 fn test_duration_nanoseconds_min_underflow() {
948 let duration = TimeDelta::nanoseconds(i64::MIN) - TimeDelta::nanoseconds(1);
951 assert!(duration.num_nanoseconds().is_none());
952 assert_eq!(
953 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
954 i64::MIN as i128 - 1
955 );
956 assert!(TimeDelta::milliseconds(-i64::MAX)
959 .checked_sub(&TimeDelta::nanoseconds(1))
960 .is_none());
961 }
962
963 #[test]
964 fn test_max() {
965 assert_eq!(
966 MAX.secs as i128 * 1_000_000_000 + MAX.nanos as i128,
967 i64::MAX as i128 * 1_000_000
968 );
969 assert_eq!(MAX, TimeDelta::milliseconds(i64::MAX));
970 assert_eq!(MAX.num_milliseconds(), i64::MAX);
971 assert_eq!(MAX.num_microseconds(), None);
972 assert_eq!(MAX.num_nanoseconds(), None);
973 }
974 #[test]
975 fn test_min() {
976 assert_eq!(
977 MIN.secs as i128 * 1_000_000_000 + MIN.nanos as i128,
978 -i64::MAX as i128 * 1_000_000
979 );
980 assert_eq!(MIN, TimeDelta::milliseconds(-i64::MAX));
981 assert_eq!(MIN.num_milliseconds(), -i64::MAX);
982 assert_eq!(MIN.num_microseconds(), None);
983 assert_eq!(MIN.num_nanoseconds(), None);
984 }
985
986 #[test]
987 fn test_duration_ord() {
988 assert!(TimeDelta::milliseconds(1) < TimeDelta::milliseconds(2));
989 assert!(TimeDelta::milliseconds(2) > TimeDelta::milliseconds(1));
990 assert!(TimeDelta::milliseconds(-1) > TimeDelta::milliseconds(-2));
991 assert!(TimeDelta::milliseconds(-2) < TimeDelta::milliseconds(-1));
992 assert!(TimeDelta::milliseconds(-1) < TimeDelta::milliseconds(1));
993 assert!(TimeDelta::milliseconds(1) > TimeDelta::milliseconds(-1));
994 assert!(TimeDelta::milliseconds(0) < TimeDelta::milliseconds(1));
995 assert!(TimeDelta::milliseconds(0) > TimeDelta::milliseconds(-1));
996 assert!(TimeDelta::milliseconds(1_001) < TimeDelta::milliseconds(1_002));
997 assert!(TimeDelta::milliseconds(-1_001) > TimeDelta::milliseconds(-1_002));
998 assert!(TimeDelta::nanoseconds(1_234_567_890) < TimeDelta::nanoseconds(1_234_567_891));
999 assert!(TimeDelta::nanoseconds(-1_234_567_890) > TimeDelta::nanoseconds(-1_234_567_891));
1000 assert!(TimeDelta::milliseconds(i64::MAX) > TimeDelta::milliseconds(i64::MAX - 1));
1001 assert!(TimeDelta::milliseconds(-i64::MAX) < TimeDelta::milliseconds(-i64::MAX + 1));
1002 }
1003
1004 #[test]
1005 fn test_duration_checked_ops() {
1006 assert_eq!(
1007 TimeDelta::milliseconds(i64::MAX).checked_add(&TimeDelta::milliseconds(0)),
1008 Some(TimeDelta::milliseconds(i64::MAX))
1009 );
1010 assert_eq!(
1011 TimeDelta::milliseconds(i64::MAX - 1).checked_add(&TimeDelta::microseconds(999)),
1012 Some(TimeDelta::milliseconds(i64::MAX - 2) + TimeDelta::microseconds(1999))
1013 );
1014 assert!(TimeDelta::milliseconds(i64::MAX)
1015 .checked_add(&TimeDelta::microseconds(1000))
1016 .is_none());
1017 assert!(TimeDelta::milliseconds(i64::MAX)
1018 .checked_add(&TimeDelta::nanoseconds(1))
1019 .is_none());
1020
1021 assert_eq!(
1022 TimeDelta::milliseconds(-i64::MAX).checked_sub(&TimeDelta::milliseconds(0)),
1023 Some(TimeDelta::milliseconds(-i64::MAX))
1024 );
1025 assert_eq!(
1026 TimeDelta::milliseconds(-i64::MAX + 1).checked_sub(&TimeDelta::microseconds(999)),
1027 Some(TimeDelta::milliseconds(-i64::MAX + 2) - TimeDelta::microseconds(1999))
1028 );
1029 assert!(TimeDelta::milliseconds(-i64::MAX)
1030 .checked_sub(&TimeDelta::milliseconds(1))
1031 .is_none());
1032 assert!(TimeDelta::milliseconds(-i64::MAX)
1033 .checked_sub(&TimeDelta::nanoseconds(1))
1034 .is_none());
1035 }
1036
1037 #[test]
1038 fn test_duration_abs() {
1039 assert_eq!(TimeDelta::milliseconds(1300).abs(), TimeDelta::milliseconds(1300));
1040 assert_eq!(TimeDelta::milliseconds(1000).abs(), TimeDelta::milliseconds(1000));
1041 assert_eq!(TimeDelta::milliseconds(300).abs(), TimeDelta::milliseconds(300));
1042 assert_eq!(TimeDelta::milliseconds(0).abs(), TimeDelta::milliseconds(0));
1043 assert_eq!(TimeDelta::milliseconds(-300).abs(), TimeDelta::milliseconds(300));
1044 assert_eq!(TimeDelta::milliseconds(-700).abs(), TimeDelta::milliseconds(700));
1045 assert_eq!(TimeDelta::milliseconds(-1000).abs(), TimeDelta::milliseconds(1000));
1046 assert_eq!(TimeDelta::milliseconds(-1300).abs(), TimeDelta::milliseconds(1300));
1047 assert_eq!(TimeDelta::milliseconds(-1700).abs(), TimeDelta::milliseconds(1700));
1048 assert_eq!(TimeDelta::milliseconds(-i64::MAX).abs(), TimeDelta::milliseconds(i64::MAX));
1049 }
1050
1051 #[test]
1052 #[allow(clippy::erasing_op)]
1053 fn test_duration_mul() {
1054 assert_eq!(TimeDelta::zero() * i32::MAX, TimeDelta::zero());
1055 assert_eq!(TimeDelta::zero() * i32::MIN, TimeDelta::zero());
1056 assert_eq!(TimeDelta::nanoseconds(1) * 0, TimeDelta::zero());
1057 assert_eq!(TimeDelta::nanoseconds(1) * 1, TimeDelta::nanoseconds(1));
1058 assert_eq!(TimeDelta::nanoseconds(1) * 1_000_000_000, TimeDelta::seconds(1));
1059 assert_eq!(TimeDelta::nanoseconds(1) * -1_000_000_000, -TimeDelta::seconds(1));
1060 assert_eq!(-TimeDelta::nanoseconds(1) * 1_000_000_000, -TimeDelta::seconds(1));
1061 assert_eq!(
1062 TimeDelta::nanoseconds(30) * 333_333_333,
1063 TimeDelta::seconds(10) - TimeDelta::nanoseconds(10)
1064 );
1065 assert_eq!(
1066 (TimeDelta::nanoseconds(1) + TimeDelta::seconds(1) + TimeDelta::days(1)) * 3,
1067 TimeDelta::nanoseconds(3) + TimeDelta::seconds(3) + TimeDelta::days(3)
1068 );
1069 assert_eq!(TimeDelta::milliseconds(1500) * -2, TimeDelta::seconds(-3));
1070 assert_eq!(TimeDelta::milliseconds(-1500) * 2, TimeDelta::seconds(-3));
1071 }
1072
1073 #[test]
1074 fn test_duration_div() {
1075 assert_eq!(TimeDelta::zero() / i32::MAX, TimeDelta::zero());
1076 assert_eq!(TimeDelta::zero() / i32::MIN, TimeDelta::zero());
1077 assert_eq!(TimeDelta::nanoseconds(123_456_789) / 1, TimeDelta::nanoseconds(123_456_789));
1078 assert_eq!(TimeDelta::nanoseconds(123_456_789) / -1, -TimeDelta::nanoseconds(123_456_789));
1079 assert_eq!(-TimeDelta::nanoseconds(123_456_789) / -1, TimeDelta::nanoseconds(123_456_789));
1080 assert_eq!(-TimeDelta::nanoseconds(123_456_789) / 1, -TimeDelta::nanoseconds(123_456_789));
1081 assert_eq!(TimeDelta::seconds(1) / 3, TimeDelta::nanoseconds(333_333_333));
1082 assert_eq!(TimeDelta::seconds(4) / 3, TimeDelta::nanoseconds(1_333_333_333));
1083 assert_eq!(TimeDelta::seconds(-1) / 2, TimeDelta::milliseconds(-500));
1084 assert_eq!(TimeDelta::seconds(1) / -2, TimeDelta::milliseconds(-500));
1085 assert_eq!(TimeDelta::seconds(-1) / -2, TimeDelta::milliseconds(500));
1086 assert_eq!(TimeDelta::seconds(-4) / 3, TimeDelta::nanoseconds(-1_333_333_333));
1087 assert_eq!(TimeDelta::seconds(-4) / -3, TimeDelta::nanoseconds(1_333_333_333));
1088 }
1089
1090 #[test]
1091 fn test_duration_sum() {
1092 let duration_list_1 = [TimeDelta::zero(), TimeDelta::seconds(1)];
1093 let sum_1: TimeDelta = duration_list_1.iter().sum();
1094 assert_eq!(sum_1, TimeDelta::seconds(1));
1095
1096 let duration_list_2 = [
1097 TimeDelta::zero(),
1098 TimeDelta::seconds(1),
1099 TimeDelta::seconds(6),
1100 TimeDelta::seconds(10),
1101 ];
1102 let sum_2: TimeDelta = duration_list_2.iter().sum();
1103 assert_eq!(sum_2, TimeDelta::seconds(17));
1104
1105 let duration_arr = [
1106 TimeDelta::zero(),
1107 TimeDelta::seconds(1),
1108 TimeDelta::seconds(6),
1109 TimeDelta::seconds(10),
1110 ];
1111 let sum_3: TimeDelta = duration_arr.into_iter().sum();
1112 assert_eq!(sum_3, TimeDelta::seconds(17));
1113 }
1114
1115 #[test]
1116 fn test_duration_fmt() {
1117 assert_eq!(TimeDelta::zero().to_string(), "P0D");
1118 assert_eq!(TimeDelta::days(42).to_string(), "PT3628800S");
1119 assert_eq!(TimeDelta::days(-42).to_string(), "-PT3628800S");
1120 assert_eq!(TimeDelta::seconds(42).to_string(), "PT42S");
1121 assert_eq!(TimeDelta::milliseconds(42).to_string(), "PT0.042S");
1122 assert_eq!(TimeDelta::microseconds(42).to_string(), "PT0.000042S");
1123 assert_eq!(TimeDelta::nanoseconds(42).to_string(), "PT0.000000042S");
1124 assert_eq!(
1125 (TimeDelta::days(7) + TimeDelta::milliseconds(6543)).to_string(),
1126 "PT604806.543S"
1127 );
1128 assert_eq!(TimeDelta::seconds(-86_401).to_string(), "-PT86401S");
1129 assert_eq!(TimeDelta::nanoseconds(-1).to_string(), "-PT0.000000001S");
1130
1131 assert_eq!(
1133 format!("{:30}", TimeDelta::days(1) + TimeDelta::milliseconds(2345)),
1134 "PT86402.345S"
1135 );
1136 }
1137
1138 #[test]
1139 fn test_to_std() {
1140 assert_eq!(TimeDelta::seconds(1).to_std(), Ok(Duration::new(1, 0)));
1141 assert_eq!(TimeDelta::seconds(86_401).to_std(), Ok(Duration::new(86_401, 0)));
1142 assert_eq!(TimeDelta::milliseconds(123).to_std(), Ok(Duration::new(0, 123_000_000)));
1143 assert_eq!(TimeDelta::milliseconds(123_765).to_std(), Ok(Duration::new(123, 765_000_000)));
1144 assert_eq!(TimeDelta::nanoseconds(777).to_std(), Ok(Duration::new(0, 777)));
1145 assert_eq!(MAX.to_std(), Ok(Duration::new(9_223_372_036_854_775, 807_000_000)));
1146 assert_eq!(TimeDelta::seconds(-1).to_std(), Err(OutOfRangeError(())));
1147 assert_eq!(TimeDelta::milliseconds(-1).to_std(), Err(OutOfRangeError(())));
1148 }
1149
1150 #[test]
1151 fn test_from_std() {
1152 assert_eq!(Ok(TimeDelta::seconds(1)), TimeDelta::from_std(Duration::new(1, 0)));
1153 assert_eq!(Ok(TimeDelta::seconds(86_401)), TimeDelta::from_std(Duration::new(86_401, 0)));
1154 assert_eq!(
1155 Ok(TimeDelta::milliseconds(123)),
1156 TimeDelta::from_std(Duration::new(0, 123_000_000))
1157 );
1158 assert_eq!(
1159 Ok(TimeDelta::milliseconds(123_765)),
1160 TimeDelta::from_std(Duration::new(123, 765_000_000))
1161 );
1162 assert_eq!(Ok(TimeDelta::nanoseconds(777)), TimeDelta::from_std(Duration::new(0, 777)));
1163 assert_eq!(Ok(MAX), TimeDelta::from_std(Duration::new(9_223_372_036_854_775, 807_000_000)));
1164 assert_eq!(
1165 TimeDelta::from_std(Duration::new(9_223_372_036_854_776, 0)),
1166 Err(OutOfRangeError(()))
1167 );
1168 assert_eq!(
1169 TimeDelta::from_std(Duration::new(9_223_372_036_854_775, 807_000_001)),
1170 Err(OutOfRangeError(()))
1171 );
1172 }
1173
1174 #[test]
1175 fn test_duration_const() {
1176 const ONE_WEEK: TimeDelta = TimeDelta::weeks(1);
1177 const ONE_DAY: TimeDelta = TimeDelta::days(1);
1178 const ONE_HOUR: TimeDelta = TimeDelta::hours(1);
1179 const ONE_MINUTE: TimeDelta = TimeDelta::minutes(1);
1180 const ONE_SECOND: TimeDelta = TimeDelta::seconds(1);
1181 const ONE_MILLI: TimeDelta = TimeDelta::milliseconds(1);
1182 const ONE_MICRO: TimeDelta = TimeDelta::microseconds(1);
1183 const ONE_NANO: TimeDelta = TimeDelta::nanoseconds(1);
1184 let combo: TimeDelta = ONE_WEEK
1185 + ONE_DAY
1186 + ONE_HOUR
1187 + ONE_MINUTE
1188 + ONE_SECOND
1189 + ONE_MILLI
1190 + ONE_MICRO
1191 + ONE_NANO;
1192
1193 assert!(ONE_WEEK != TimeDelta::zero());
1194 assert!(ONE_DAY != TimeDelta::zero());
1195 assert!(ONE_HOUR != TimeDelta::zero());
1196 assert!(ONE_MINUTE != TimeDelta::zero());
1197 assert!(ONE_SECOND != TimeDelta::zero());
1198 assert!(ONE_MILLI != TimeDelta::zero());
1199 assert!(ONE_MICRO != TimeDelta::zero());
1200 assert!(ONE_NANO != TimeDelta::zero());
1201 assert_eq!(
1202 combo,
1203 TimeDelta::seconds(86400 * 7 + 86400 + 3600 + 60 + 1)
1204 + TimeDelta::nanoseconds(1 + 1_000 + 1_000_000)
1205 );
1206 }
1207
1208 #[test]
1209 #[cfg(feature = "rkyv-validation")]
1210 fn test_rkyv_validation() {
1211 let duration = TimeDelta::seconds(1);
1212 let bytes = rkyv::to_bytes::<_, 16>(&duration).unwrap();
1213 assert_eq!(rkyv::from_bytes::<TimeDelta>(&bytes).unwrap(), duration);
1214 }
1215}