diff --git a/CHANGELOG.md b/CHANGELOG.md index dc3a65642b..8ac5ebcb85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ Versions with only mechanical changes will be omitted from the following list. * Add support for getting week bounds based on a specific `NaiveDate` and a `Weekday` (#666) * Remove libc dependency from Cargo.toml. * Add the `and_local_timezone` method to `NaiveDateTime` +* Fix the behavior of `Duration::abs()` for negative durations with non-zero nanos ## 0.4.19 diff --git a/src/oldtime.rs b/src/oldtime.rs index eb0c5bcf20..53ad546725 100644 --- a/src/oldtime.rs +++ b/src/oldtime.rs @@ -249,7 +249,11 @@ impl Duration { /// Returns the duration as an absolute (non-negative) value. #[inline] pub fn abs(&self) -> Duration { - Duration { secs: self.secs.abs(), nanos: self.nanos } + if self.secs < 0 && self.nanos != 0 { + Duration { secs: (self.secs + 1).abs(), nanos: NANOS_PER_SEC - self.nanos } + } else { + Duration { secs: self.secs.abs(), nanos: self.nanos } + } } /// The minimum possible `Duration`: `i64::MIN` milliseconds. @@ -610,6 +614,19 @@ mod tests { assert!(Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(1)).is_none()); } + #[test] + fn test_duration_abs() { + assert_eq!(Duration::milliseconds(1300).abs(), Duration::milliseconds(1300)); + assert_eq!(Duration::milliseconds(1000).abs(), Duration::milliseconds(1000)); + assert_eq!(Duration::milliseconds(300).abs(), Duration::milliseconds(300)); + assert_eq!(Duration::milliseconds(0).abs(), Duration::milliseconds(0)); + assert_eq!(Duration::milliseconds(-300).abs(), Duration::milliseconds(300)); + assert_eq!(Duration::milliseconds(-700).abs(), Duration::milliseconds(700)); + assert_eq!(Duration::milliseconds(-1000).abs(), Duration::milliseconds(1000)); + assert_eq!(Duration::milliseconds(-1300).abs(), Duration::milliseconds(1300)); + assert_eq!(Duration::milliseconds(-1700).abs(), Duration::milliseconds(1700)); + } + #[test] fn test_duration_mul() { assert_eq!(Duration::zero() * i32::MAX, Duration::zero());