diff --git a/tests/duration.rs b/tests/duration.rs index ef0064fa4..99990efef 100644 --- a/tests/duration.rs +++ b/tests/duration.rs @@ -480,6 +480,15 @@ fn checked_div_regression() { Some(Duration::new(0, 142_857_143)) // manually verified ); } + +#[rstest] +#[case(5.seconds(), Some((-5).seconds()))] +#[case((-5).seconds(), Some(5.seconds()))] +#[case(Duration::MIN, None)] +fn checked_neg(#[case] duration: Duration, #[case] expected: Option) { + assert_eq!(duration.checked_neg(), expected); +} + #[rstest] #[case(5.seconds(), 5.seconds(), 10.seconds())] #[case(Duration::MAX, 1.nanoseconds(), Duration::MAX)] diff --git a/time/src/duration.rs b/time/src/duration.rs index 9495509f6..788f73748 100644 --- a/time/src/duration.rs +++ b/time/src/duration.rs @@ -1023,6 +1023,25 @@ impl Duration { // Safety: `nanoseconds` is in range. unsafe { Some(Self::new_unchecked(secs, nanos)) } } + + /// Computes `-self`, returning `None` if the result would overflow. + /// + /// ```rust + /// # use time::ext::NumericalDuration; + /// # use time::Duration; + /// assert_eq!(5.seconds().checked_neg(), Some((-5).seconds())); + /// assert_eq!(Duration::MIN.checked_neg(), None); + /// ``` + pub const fn checked_neg(self) -> Option { + if self.seconds == i64::MIN { + None + } else { + Some(Self::new_ranged_unchecked( + -self.seconds, + self.nanoseconds.neg(), + )) + } + } // endregion checked arithmetic // region: saturating arithmetic @@ -1338,7 +1357,7 @@ impl Neg for Duration { type Output = Self; fn neg(self) -> Self::Output { - Self::new_ranged_unchecked(-self.seconds, self.nanoseconds.neg()) + self.checked_neg().expect("overflow when negating duration") } }