From de2c31928fd56e05c06ac2733b8bbd5452639d44 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Mon, 25 Sep 2023 11:15:12 +0200 Subject: [PATCH 1/7] Use `expect` instead of `unwrap` in `Add` and `Sub` impls --- src/datetime/mod.rs | 14 ++++++++------ src/naive/date.rs | 8 ++++---- src/naive/datetime/mod.rs | 12 ++++++------ 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index 59178743dc..b05744e653 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -1252,7 +1252,8 @@ impl Add for DateTime { #[inline] fn add(mut self, rhs: FixedOffset) -> DateTime { - self.datetime = self.naive_utc().checked_add_offset(rhs).unwrap(); + self.datetime = + self.naive_utc().checked_add_offset(rhs).expect("`DateTime + FixedOffset` overflowed"); self } } @@ -1261,7 +1262,7 @@ impl Add for DateTime { type Output = DateTime; fn add(self, rhs: Months) -> Self::Output { - self.checked_add_months(rhs).unwrap() + self.checked_add_months(rhs).expect("`DateTime + Months` out of range") } } @@ -1309,7 +1310,8 @@ impl Sub for DateTime { #[inline] fn sub(mut self, rhs: FixedOffset) -> DateTime { - self.datetime = self.naive_utc().checked_sub_offset(rhs).unwrap(); + self.datetime = + self.naive_utc().checked_sub_offset(rhs).expect("`DateTime - FixedOffset` overflowed"); self } } @@ -1318,7 +1320,7 @@ impl Sub for DateTime { type Output = DateTime; fn sub(self, rhs: Months) -> Self::Output { - self.checked_sub_months(rhs).unwrap() + self.checked_sub_months(rhs).expect("`DateTime - Months` out of range") } } @@ -1344,7 +1346,7 @@ impl Add for DateTime { type Output = DateTime; fn add(self, days: Days) -> Self::Output { - self.checked_add_days(days).unwrap() + self.checked_add_days(days).expect("`DateTime + Days` out of range") } } @@ -1352,7 +1354,7 @@ impl Sub for DateTime { type Output = DateTime; fn sub(self, days: Days) -> Self::Output { - self.checked_sub_days(days).unwrap() + self.checked_sub_days(days).expect("`DateTime - Days` out of range") } } diff --git a/src/naive/date.rs b/src/naive/date.rs index 700958e171..4b3cbe84bd 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -1889,7 +1889,7 @@ impl Add for NaiveDate { /// assert_eq!(from_ymd(2020, 1, 31) + Months::new(1), from_ymd(2020, 2, 29)); /// ``` fn add(self, months: Months) -> Self::Output { - self.checked_add_months(months).unwrap() + self.checked_add_months(months).expect("`NaiveDate + Months` out of range") } } @@ -1914,7 +1914,7 @@ impl Sub for NaiveDate { /// assert_eq!(from_ymd(2014, 1, 1) - Months::new(13), from_ymd(2012, 12, 1)); /// ``` fn sub(self, months: Months) -> Self::Output { - self.checked_sub_months(months).unwrap() + self.checked_sub_months(months).expect("`NaiveDate - Months` out of range") } } @@ -1922,7 +1922,7 @@ impl Add for NaiveDate { type Output = NaiveDate; fn add(self, days: Days) -> Self::Output { - self.checked_add_days(days).unwrap() + self.checked_add_days(days).expect("`NaiveDate + Days` out of range") } } @@ -1930,7 +1930,7 @@ impl Sub for NaiveDate { type Output = NaiveDate; fn sub(self, days: Days) -> Self::Output { - self.checked_sub_days(days).unwrap() + self.checked_sub_days(days).expect("`NaiveDate - Days` out of range") } } diff --git a/src/naive/datetime/mod.rs b/src/naive/datetime/mod.rs index 67e12c71f7..69ae76613b 100644 --- a/src/naive/datetime/mod.rs +++ b/src/naive/datetime/mod.rs @@ -1624,7 +1624,7 @@ impl Add for NaiveDateTime { #[inline] fn add(self, rhs: FixedOffset) -> NaiveDateTime { - self.checked_add_offset(rhs).unwrap() + self.checked_add_offset(rhs).expect("`NaiveDateTime + FixedOffset` out of range") } } @@ -1668,7 +1668,7 @@ impl Add for NaiveDateTime { /// ); /// ``` fn add(self, rhs: Months) -> Self::Output { - Self { date: self.date.checked_add_months(rhs).unwrap(), time: self.time } + self.checked_add_months(rhs).expect("`NaiveDateTime + Months` out of range") } } @@ -1760,7 +1760,7 @@ impl Sub for NaiveDateTime { #[inline] fn sub(self, rhs: FixedOffset) -> NaiveDateTime { - self.checked_sub_offset(rhs).unwrap() + self.checked_sub_offset(rhs).expect("`NaiveDateTime - FixedOffset` out of range") } } @@ -1792,7 +1792,7 @@ impl Sub for NaiveDateTime { type Output = NaiveDateTime; fn sub(self, rhs: Months) -> Self::Output { - Self { date: self.date.checked_sub_months(rhs).unwrap(), time: self.time } + self.checked_sub_months(rhs).expect("`NaiveDateTime - Months` out of range") } } @@ -1848,7 +1848,7 @@ impl Add for NaiveDateTime { type Output = NaiveDateTime; fn add(self, days: Days) -> Self::Output { - self.checked_add_days(days).unwrap() + self.checked_add_days(days).expect("`NaiveDateTime + Days` out of range") } } @@ -1856,7 +1856,7 @@ impl Sub for NaiveDateTime { type Output = NaiveDateTime; fn sub(self, days: Days) -> Self::Output { - self.checked_sub_days(days).unwrap() + self.checked_sub_days(days).expect("`NaiveDateTime - Days` out of range") } } From 76fca80860505b1722eb2abd00b92a97839605b4 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Mon, 25 Sep 2023 16:33:53 +0200 Subject: [PATCH 2/7] Clamp `std::time::Duration` before converting to prevent panic --- src/naive/time/mod.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/naive/time/mod.rs b/src/naive/time/mod.rs index b9de19d0cb..46a3ca4697 100644 --- a/src/naive/time/mod.rs +++ b/src/naive/time/mod.rs @@ -1165,18 +1165,19 @@ impl Add for NaiveTime { #[inline] fn add(self, rhs: Duration) -> NaiveTime { - let rhs = OldDuration::from_std(rhs) - .expect("overflow converting from core::time::Duration to chrono::Duration"); - self.overflowing_add_signed(rhs).0 + // We don't care about values beyond `24 * 60 * 60`, so we can take a modulus and avoid + // overflow during the conversion to `chrono::Duration`. + // But we limit to double that just in case `self` is a leap-second. + let secs = rhs.as_secs() % (2 * 24 * 60 * 60); + let d = OldDuration::from_std(Duration::new(secs, rhs.subsec_nanos())).unwrap(); + self.overflowing_add_signed(d).0 } } impl AddAssign for NaiveTime { #[inline] fn add_assign(&mut self, rhs: Duration) { - let rhs = OldDuration::from_std(rhs) - .expect("overflow converting from core::time::Duration to chrono::Duration"); - *self += rhs; + *self = *self + rhs; } } @@ -1256,18 +1257,19 @@ impl Sub for NaiveTime { #[inline] fn sub(self, rhs: Duration) -> NaiveTime { - let rhs = OldDuration::from_std(rhs) - .expect("overflow converting from core::time::Duration to chrono::Duration"); - self.overflowing_sub_signed(rhs).0 + // We don't care about values beyond `24 * 60 * 60`, so we can take a modulus and avoid + // overflow during the conversion to `chrono::Duration`. + // But we limit to double that just in case `self` is a leap-second. + let secs = rhs.as_secs() % (2 * 24 * 60 * 60); + let d = OldDuration::from_std(Duration::new(secs, rhs.subsec_nanos())).unwrap(); + self.overflowing_sub_signed(d).0 } } impl SubAssign for NaiveTime { #[inline] fn sub_assign(&mut self, rhs: Duration) { - let rhs = OldDuration::from_std(rhs) - .expect("overflow converting from core::time::Duration to chrono::Duration"); - *self -= rhs; + *self = *self - rhs; } } From 9bc59b5bb1fed5f8a82b25cb8964830b8b0bc477 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Mon, 25 Sep 2023 10:21:05 +0200 Subject: [PATCH 3/7] Move doc comments from method to trait (for consistency) --- src/naive/date.rs | 74 +++++++++++++++++++-------------------- src/naive/datetime/mod.rs | 72 ++++++++++++++++++------------------- 2 files changed, 73 insertions(+), 73 deletions(-) diff --git a/src/naive/date.rs b/src/naive/date.rs index 4b3cbe84bd..3b41640f8c 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -1865,54 +1865,54 @@ impl AddAssign for NaiveDate { } } +/// An addition of months to `NaiveDate` clamped to valid days in resulting month. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// +/// # Example +/// +/// ``` +/// use chrono::{NaiveDate, Months}; +/// +/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); +/// +/// assert_eq!(from_ymd(2014, 1, 1) + Months::new(1), from_ymd(2014, 2, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) + Months::new(11), from_ymd(2014, 12, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) + Months::new(12), from_ymd(2015, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) + Months::new(13), from_ymd(2015, 2, 1)); +/// assert_eq!(from_ymd(2014, 1, 31) + Months::new(1), from_ymd(2014, 2, 28)); +/// assert_eq!(from_ymd(2020, 1, 31) + Months::new(1), from_ymd(2020, 2, 29)); +/// ``` impl Add for NaiveDate { type Output = NaiveDate; - /// An addition of months to `NaiveDate` clamped to valid days in resulting month. - /// - /// # Panics - /// - /// Panics if the resulting date would be out of range. - /// - /// # Example - /// - /// ``` - /// use chrono::{NaiveDate, Months}; - /// - /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); - /// - /// assert_eq!(from_ymd(2014, 1, 1) + Months::new(1), from_ymd(2014, 2, 1)); - /// assert_eq!(from_ymd(2014, 1, 1) + Months::new(11), from_ymd(2014, 12, 1)); - /// assert_eq!(from_ymd(2014, 1, 1) + Months::new(12), from_ymd(2015, 1, 1)); - /// assert_eq!(from_ymd(2014, 1, 1) + Months::new(13), from_ymd(2015, 2, 1)); - /// assert_eq!(from_ymd(2014, 1, 31) + Months::new(1), from_ymd(2014, 2, 28)); - /// assert_eq!(from_ymd(2020, 1, 31) + Months::new(1), from_ymd(2020, 2, 29)); - /// ``` fn add(self, months: Months) -> Self::Output { self.checked_add_months(months).expect("`NaiveDate + Months` out of range") } } +/// A subtraction of Months from `NaiveDate` clamped to valid days in resulting month. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// +/// # Example +/// +/// ``` +/// use chrono::{NaiveDate, Months}; +/// +/// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); +/// +/// assert_eq!(from_ymd(2014, 1, 1) - Months::new(11), from_ymd(2013, 2, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) - Months::new(12), from_ymd(2013, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) - Months::new(13), from_ymd(2012, 12, 1)); +/// ``` impl Sub for NaiveDate { type Output = NaiveDate; - /// A subtraction of Months from `NaiveDate` clamped to valid days in resulting month. - /// - /// # Panics - /// - /// Panics if the resulting date would be out of range. - /// - /// # Example - /// - /// ``` - /// use chrono::{NaiveDate, Months}; - /// - /// let from_ymd = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap(); - /// - /// assert_eq!(from_ymd(2014, 1, 1) - Months::new(11), from_ymd(2013, 2, 1)); - /// assert_eq!(from_ymd(2014, 1, 1) - Months::new(12), from_ymd(2013, 1, 1)); - /// assert_eq!(from_ymd(2014, 1, 1) - Months::new(13), from_ymd(2012, 12, 1)); - /// ``` fn sub(self, months: Months) -> Self::Output { self.checked_sub_months(months).expect("`NaiveDate - Months` out of range") } diff --git a/src/naive/datetime/mod.rs b/src/naive/datetime/mod.rs index 69ae76613b..06ddf7ebb1 100644 --- a/src/naive/datetime/mod.rs +++ b/src/naive/datetime/mod.rs @@ -1628,45 +1628,45 @@ impl Add for NaiveDateTime { } } +/// An addition of months to `NaiveDateTime` clamped to valid days in resulting month. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// +/// # Example +/// +/// ``` +/// use chrono::{Months, NaiveDate}; +/// +/// assert_eq!( +/// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(1, 0, 0).unwrap() + Months::new(1), +/// NaiveDate::from_ymd_opt(2014, 2, 1).unwrap().and_hms_opt(1, 0, 0).unwrap() +/// ); +/// assert_eq!( +/// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(0, 2, 0).unwrap() + Months::new(11), +/// NaiveDate::from_ymd_opt(2014, 12, 1).unwrap().and_hms_opt(0, 2, 0).unwrap() +/// ); +/// assert_eq!( +/// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(0, 0, 3).unwrap() + Months::new(12), +/// NaiveDate::from_ymd_opt(2015, 1, 1).unwrap().and_hms_opt(0, 0, 3).unwrap() +/// ); +/// assert_eq!( +/// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(0, 0, 4).unwrap() + Months::new(13), +/// NaiveDate::from_ymd_opt(2015, 2, 1).unwrap().and_hms_opt(0, 0, 4).unwrap() +/// ); +/// assert_eq!( +/// NaiveDate::from_ymd_opt(2014, 1, 31).unwrap().and_hms_opt(0, 5, 0).unwrap() + Months::new(1), +/// NaiveDate::from_ymd_opt(2014, 2, 28).unwrap().and_hms_opt(0, 5, 0).unwrap() +/// ); +/// assert_eq!( +/// NaiveDate::from_ymd_opt(2020, 1, 31).unwrap().and_hms_opt(6, 0, 0).unwrap() + Months::new(1), +/// NaiveDate::from_ymd_opt(2020, 2, 29).unwrap().and_hms_opt(6, 0, 0).unwrap() +/// ); +/// ``` impl Add for NaiveDateTime { type Output = NaiveDateTime; - /// An addition of months to `NaiveDateTime` clamped to valid days in resulting month. - /// - /// # Panics - /// - /// Panics if the resulting date would be out of range. - /// - /// # Example - /// - /// ``` - /// use chrono::{Months, NaiveDate}; - /// - /// assert_eq!( - /// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(1, 0, 0).unwrap() + Months::new(1), - /// NaiveDate::from_ymd_opt(2014, 2, 1).unwrap().and_hms_opt(1, 0, 0).unwrap() - /// ); - /// assert_eq!( - /// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(0, 2, 0).unwrap() + Months::new(11), - /// NaiveDate::from_ymd_opt(2014, 12, 1).unwrap().and_hms_opt(0, 2, 0).unwrap() - /// ); - /// assert_eq!( - /// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(0, 0, 3).unwrap() + Months::new(12), - /// NaiveDate::from_ymd_opt(2015, 1, 1).unwrap().and_hms_opt(0, 0, 3).unwrap() - /// ); - /// assert_eq!( - /// NaiveDate::from_ymd_opt(2014, 1, 1).unwrap().and_hms_opt(0, 0, 4).unwrap() + Months::new(13), - /// NaiveDate::from_ymd_opt(2015, 2, 1).unwrap().and_hms_opt(0, 0, 4).unwrap() - /// ); - /// assert_eq!( - /// NaiveDate::from_ymd_opt(2014, 1, 31).unwrap().and_hms_opt(0, 5, 0).unwrap() + Months::new(1), - /// NaiveDate::from_ymd_opt(2014, 2, 28).unwrap().and_hms_opt(0, 5, 0).unwrap() - /// ); - /// assert_eq!( - /// NaiveDate::from_ymd_opt(2020, 1, 31).unwrap().and_hms_opt(6, 0, 0).unwrap() + Months::new(1), - /// NaiveDate::from_ymd_opt(2020, 2, 29).unwrap().and_hms_opt(6, 0, 0).unwrap() - /// ); - /// ``` fn add(self, rhs: Months) -> Self::Output { self.checked_add_months(rhs).expect("`NaiveDateTime + Months` out of range") } From 0ed0618c92b9c00cec5f5baddfbe5fba994198ef Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Mon, 25 Sep 2023 10:22:05 +0200 Subject: [PATCH 4/7] Consistently document `Add` and `Sub` impls of `NaiveDate` --- src/naive/date.rs | 65 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 8 deletions(-) diff --git a/src/naive/date.rs b/src/naive/date.rs index 3b41640f8c..9677b0c439 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -1826,10 +1826,15 @@ impl Datelike for NaiveDate { } } -/// An addition of `Duration` to `NaiveDate` discards the fractional days, -/// rounding to the closest integral number of days towards `Duration::zero()`. +/// Add `chrono::Duration` to `NaiveDate`. /// -/// Panics on underflow or overflow. Use [`NaiveDate::checked_add_signed`] to detect that. +/// This discards the fractional days in `Duration`, rounding to the closest integral number of days +/// towards `Duration::zero()`. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using [`NaiveDate::checked_add_signed`] to get an `Option` instead. /// /// # Example /// @@ -1858,6 +1863,15 @@ impl Add for NaiveDate { } } +/// Add-assign of `chrono::Duration` to `NaiveDate`. +/// +/// This discards the fractional days in `Duration`, rounding to the closest integral number of days +/// towards `Duration::zero()`. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using [`NaiveDate::checked_add_signed`] to get an `Option` instead. impl AddAssign for NaiveDate { #[inline] fn add_assign(&mut self, rhs: OldDuration) { @@ -1865,11 +1879,15 @@ impl AddAssign for NaiveDate { } } -/// An addition of months to `NaiveDate` clamped to valid days in resulting month. +/// Add `Months` to `NaiveDate`. +/// +/// The result will be clamped to valid days in the resulting month, see `checked_add_months` for +/// details. /// /// # Panics /// /// Panics if the resulting date would be out of range. +/// Consider using `NaiveDate::checked_add_months` to get an `Option` instead. /// /// # Example /// @@ -1893,11 +1911,15 @@ impl Add for NaiveDate { } } -/// A subtraction of Months from `NaiveDate` clamped to valid days in resulting month. +/// Subtract `Months` from `NaiveDate`. +/// +/// The result will be clamped to valid days in the resulting month, see `checked_sub_months` for +/// details. /// /// # Panics /// /// Panics if the resulting date would be out of range. +/// Consider using `NaiveDate::checked_sub_months` to get an `Option` instead. /// /// # Example /// @@ -1918,6 +1940,12 @@ impl Sub for NaiveDate { } } +/// Add `Days` to `NaiveDate`. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using `NaiveDate::checked_add_days` to get an `Option` instead. impl Add for NaiveDate { type Output = NaiveDate; @@ -1926,6 +1954,12 @@ impl Add for NaiveDate { } } +/// Subtract `Days` from `NaiveDate`. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using `NaiveDate::checked_sub_days` to get an `Option` instead. impl Sub for NaiveDate { type Output = NaiveDate; @@ -1934,11 +1968,16 @@ impl Sub for NaiveDate { } } -/// A subtraction of `Duration` from `NaiveDate` discards the fractional days, -/// rounding to the closest integral number of days towards `Duration::zero()`. +/// Subtract `chrono::Duration` from `NaiveDate`. +/// +/// This discards the fractional days in `Duration`, rounding to the closest integral number of days +/// towards `Duration::zero()`. /// It is the same as the addition with a negated `Duration`. /// -/// Panics on underflow or overflow. Use [`NaiveDate::checked_sub_signed`] to detect that. +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using [`NaiveDate::checked_sub_signed`] to get an `Option` instead. /// /// # Example /// @@ -1967,6 +2006,16 @@ impl Sub for NaiveDate { } } +/// Subtract-assign `chrono::Duration` from `NaiveDate`. +/// +/// This discards the fractional days in `Duration`, rounding to the closest integral number of days +/// towards `Duration::zero()`. +/// It is the same as the addition with a negated `Duration`. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using [`NaiveDate::checked_sub_signed`] to get an `Option` instead. impl SubAssign for NaiveDate { #[inline] fn sub_assign(&mut self, rhs: OldDuration) { From 48744dffea7b03bc8cccf94b72489e2c749ff29d Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Mon, 25 Sep 2023 16:13:15 +0200 Subject: [PATCH 5/7] Document `Add` and `Sub` impls of `NaiveTime` --- src/naive/time/mod.rs | 44 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/src/naive/time/mod.rs b/src/naive/time/mod.rs index 46a3ca4697..8418ffc29c 100644 --- a/src/naive/time/mod.rs +++ b/src/naive/time/mod.rs @@ -1094,7 +1094,9 @@ impl Timelike for NaiveTime { } } -/// An addition of `Duration` to `NaiveTime` wraps around and never overflows or underflows. +/// Add `chrono::Duration` to `NaiveTime`. +/// +/// This wraps around and never overflows or underflows. /// In particular the addition ignores integral number of days. /// /// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap @@ -1153,6 +1155,10 @@ impl Add for NaiveTime { } } +/// Add-assign `chrono::Duration` to `NaiveTime`. +/// +/// This wraps around and never overflows or underflows. +/// In particular the addition ignores integral number of days. impl AddAssign for NaiveTime { #[inline] fn add_assign(&mut self, rhs: OldDuration) { @@ -1160,6 +1166,10 @@ impl AddAssign for NaiveTime { } } +/// Add `std::time::Duration` to `NaiveTime`. +/// +/// This wraps around and never overflows or underflows. +/// In particular the addition ignores integral number of days. impl Add for NaiveTime { type Output = NaiveTime; @@ -1174,6 +1184,10 @@ impl Add for NaiveTime { } } +/// Add-assign `std::time::Duration` to `NaiveTime`. +/// +/// This wraps around and never overflows or underflows. +/// In particular the addition ignores integral number of days. impl AddAssign for NaiveTime { #[inline] fn add_assign(&mut self, rhs: Duration) { @@ -1181,6 +1195,10 @@ impl AddAssign for NaiveTime { } } +/// Add `FixedOffset` to `NaiveTime`. +/// +/// This wraps around and never overflows or underflows. +/// In particular the addition ignores integral number of days. impl Add for NaiveTime { type Output = NaiveTime; @@ -1190,9 +1208,11 @@ impl Add for NaiveTime { } } -/// A subtraction of `Duration` from `NaiveTime` wraps around and never overflows or underflows. -/// In particular the addition ignores integral number of days. -/// It is the same as the addition with a negated `Duration`. +/// Subtract `chrono::Duration` from `NaiveTime`. +/// +/// This wraps around and never overflows or underflows. +/// In particular the subtraction ignores integral number of days. +/// This is the same as addition with a negated `Duration`. /// /// As a part of Chrono's [leap second handling], the subtraction assumes that **there is no leap /// second ever**, except when the `NaiveTime` itself represents a leap second in which case the @@ -1245,6 +1265,10 @@ impl Sub for NaiveTime { } } +/// Subtract-assign `chrono::Duration` from `NaiveTime`. +/// +/// This wraps around and never overflows or underflows. +/// In particular the subtraction ignores integral number of days. impl SubAssign for NaiveTime { #[inline] fn sub_assign(&mut self, rhs: OldDuration) { @@ -1252,6 +1276,10 @@ impl SubAssign for NaiveTime { } } +/// Subtract `std::time::Duration` from `NaiveTime`. +/// +/// This wraps around and never overflows or underflows. +/// In particular the subtraction ignores integral number of days. impl Sub for NaiveTime { type Output = NaiveTime; @@ -1266,6 +1294,10 @@ impl Sub for NaiveTime { } } +/// Subtract-assign `std::time::Duration` from `NaiveTime`. +/// +/// This wraps around and never overflows or underflows. +/// In particular the subtraction ignores integral number of days. impl SubAssign for NaiveTime { #[inline] fn sub_assign(&mut self, rhs: Duration) { @@ -1273,6 +1305,10 @@ impl SubAssign for NaiveTime { } } +/// Subtract `FixedOffset` from `NaiveTime`. +/// +/// This wraps around and never overflows or underflows. +/// In particular the subtraction ignores integral number of days. impl Sub for NaiveTime { type Output = NaiveTime; From 96019e47f70d8e21edde338eb86cc9af9a6ebd0d Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Mon, 25 Sep 2023 10:54:00 +0200 Subject: [PATCH 6/7] Consistently document `Add` and `Sub` impls of `NaiveDateTime` --- src/naive/datetime/mod.rs | 115 +++++++++++++++++++++++++++++++++++--- 1 file changed, 106 insertions(+), 9 deletions(-) diff --git a/src/naive/datetime/mod.rs b/src/naive/datetime/mod.rs index 06ddf7ebb1..af399d8a67 100644 --- a/src/naive/datetime/mod.rs +++ b/src/naive/datetime/mod.rs @@ -1533,7 +1533,7 @@ impl Timelike for NaiveDateTime { } } -/// An addition of `Duration` to `NaiveDateTime` yields another `NaiveDateTime`. +/// Add `chrono::Duration` to `NaiveDateTime`. /// /// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap /// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case @@ -1541,8 +1541,8 @@ impl Timelike for NaiveDateTime { /// /// # Panics /// -/// Panics if the resulting date would be out of range. Use [`NaiveDateTime::checked_add_signed`] -/// to detect that. +/// Panics if the resulting date would be out of range. +/// Consider using [`NaiveDateTime::checked_add_signed`] to get an `Option` instead. /// /// # Example /// @@ -1594,6 +1594,16 @@ impl Add for NaiveDateTime { } } +/// Add `std::time::Duration` to `NaiveDateTime`. +/// +/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap +/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case +/// the assumption becomes that **there is exactly a single leap second ever**. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using [`NaiveDateTime::checked_add_signed`] to get an `Option` instead. impl Add for NaiveDateTime { type Output = NaiveDateTime; @@ -1605,6 +1615,16 @@ impl Add for NaiveDateTime { } } +/// Add-assign `chrono::Duration` to `NaiveDateTime`. +/// +/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap +/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case +/// the assumption becomes that **there is exactly a single leap second ever**. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using [`NaiveDateTime::checked_add_signed`] to get an `Option` instead. impl AddAssign for NaiveDateTime { #[inline] fn add_assign(&mut self, rhs: OldDuration) { @@ -1612,6 +1632,16 @@ impl AddAssign for NaiveDateTime { } } +/// Add-assign `std::time::Duration` to `NaiveDateTime`. +/// +/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap +/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case +/// the assumption becomes that **there is exactly a single leap second ever**. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using [`NaiveDateTime::checked_add_signed`] to get an `Option` instead. impl AddAssign for NaiveDateTime { #[inline] fn add_assign(&mut self, rhs: Duration) { @@ -1619,6 +1649,12 @@ impl AddAssign for NaiveDateTime { } } +/// Add `FixedOffset` to `NaiveDateTime`. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using `checked_add_offset` to get an `Option` instead. impl Add for NaiveDateTime { type Output = NaiveDateTime; @@ -1628,11 +1664,15 @@ impl Add for NaiveDateTime { } } -/// An addition of months to `NaiveDateTime` clamped to valid days in resulting month. +/// Add `Months` to `NaiveDateTime`. +/// +/// The result will be clamped to valid days in the resulting month, see `checked_add_months` for +/// details. /// /// # Panics /// /// Panics if the resulting date would be out of range. +/// Consider using `checked_add_months` to get an `Option` instead. /// /// # Example /// @@ -1672,15 +1712,18 @@ impl Add for NaiveDateTime { } } -/// A subtraction of `Duration` from `NaiveDateTime` yields another `NaiveDateTime`. -/// It is the same as the addition with a negated `Duration`. +/// Subtract `chrono::Duration` from `NaiveDateTime`. +/// +/// This is the same as the addition with a negated `Duration`. /// /// As a part of Chrono's [leap second handling] the subtraction assumes that **there is no leap /// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case /// the assumption becomes that **there is exactly a single leap second ever**. /// -/// Panics on underflow or overflow. Use [`NaiveDateTime::checked_sub_signed`] -/// to detect that. +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using [`NaiveDateTime::checked_sub_signed`] to get an `Option` instead. /// /// # Example /// @@ -1730,6 +1773,16 @@ impl Sub for NaiveDateTime { } } +/// Subtract `std::time::Duration` from `NaiveDateTime`. +/// +/// As a part of Chrono's [leap second handling] the subtraction assumes that **there is no leap +/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case +/// the assumption becomes that **there is exactly a single leap second ever**. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using [`NaiveDateTime::checked_sub_signed`] to get an `Option` instead. impl Sub for NaiveDateTime { type Output = NaiveDateTime; @@ -1741,6 +1794,18 @@ impl Sub for NaiveDateTime { } } +/// Subtract-assign `chrono::Duration` from `NaiveDateTime`. +/// +/// This is the same as the addition with a negated `Duration`. +/// +/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap +/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case +/// the assumption becomes that **there is exactly a single leap second ever**. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using [`NaiveDateTime::checked_sub_signed`] to get an `Option` instead. impl SubAssign for NaiveDateTime { #[inline] fn sub_assign(&mut self, rhs: OldDuration) { @@ -1748,6 +1813,16 @@ impl SubAssign for NaiveDateTime { } } +/// Subtract-assign `std::time::Duration` from `NaiveDateTime`. +/// +/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap +/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case +/// the assumption becomes that **there is exactly a single leap second ever**. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using [`NaiveDateTime::checked_sub_signed`] to get an `Option` instead. impl SubAssign for NaiveDateTime { #[inline] fn sub_assign(&mut self, rhs: Duration) { @@ -1755,6 +1830,12 @@ impl SubAssign for NaiveDateTime { } } +/// Subtract `FixedOffset` from `NaiveDateTime`. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using `checked_sub_offset` to get an `Option` instead. impl Sub for NaiveDateTime { type Output = NaiveDateTime; @@ -1764,11 +1845,15 @@ impl Sub for NaiveDateTime { } } -/// A subtraction of Months from `NaiveDateTime` clamped to valid days in resulting month. +/// Subtract `Months` from `NaiveDateTime`. +/// +/// The result will be clamped to valid days in the resulting month, see +/// [`NaiveDateTime::checked_sub_months`] for details. /// /// # Panics /// /// Panics if the resulting date would be out of range. +/// Consider using [`NaiveDateTime::checked_sub_months`] to get an `Option` instead. /// /// # Example /// @@ -1844,6 +1929,12 @@ impl Sub for NaiveDateTime { } } +/// Add `Days` to `NaiveDateTime`. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using `checked_add_days` to get an `Option` instead. impl Add for NaiveDateTime { type Output = NaiveDateTime; @@ -1852,6 +1943,12 @@ impl Add for NaiveDateTime { } } +/// Subtract `Days` from `NaiveDateTime`. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using `checked_sub_days` to get an `Option` instead. impl Sub for NaiveDateTime { type Output = NaiveDateTime; From cdecf2adcf870f4b948d91f12400390bc4c8ded4 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Mon, 25 Sep 2023 12:28:06 +0200 Subject: [PATCH 7/7] Document `Add` and `Sub` impls of `DateTime` --- src/datetime/mod.rs | 140 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index b05744e653..3efd303817 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -1208,6 +1208,16 @@ impl hash::Hash for DateTime { } } +/// Add `chrono::Duration` to `DateTime`. +/// +/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap +/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case +/// the assumption becomes that **there is exactly a single leap second ever**. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using [`DateTime::checked_add_signed`] to get an `Option` instead. impl Add for DateTime { type Output = DateTime; @@ -1217,6 +1227,16 @@ impl Add for DateTime { } } +/// Add `std::time::Duration` to `DateTime`. +/// +/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap +/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case +/// the assumption becomes that **there is exactly a single leap second ever**. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using [`DateTime::checked_add_signed`] to get an `Option` instead. impl Add for DateTime { type Output = DateTime; @@ -1228,6 +1248,16 @@ impl Add for DateTime { } } +/// Add-assign `chrono::Duration` to `DateTime`. +/// +/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap +/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case +/// the assumption becomes that **there is exactly a single leap second ever**. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using [`DateTime::checked_add_signed`] to get an `Option` instead. impl AddAssign for DateTime { #[inline] fn add_assign(&mut self, rhs: OldDuration) { @@ -1238,6 +1268,16 @@ impl AddAssign for DateTime { } } +/// Add-assign `std::time::Duration` to `DateTime`. +/// +/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap +/// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case +/// the assumption becomes that **there is exactly a single leap second ever**. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using [`DateTime::checked_add_signed`] to get an `Option` instead. impl AddAssign for DateTime { #[inline] fn add_assign(&mut self, rhs: Duration) { @@ -1247,6 +1287,11 @@ impl AddAssign for DateTime { } } +/// Add `FixedOffset` to the datetime value of `DateTime` (offset remains unchanged). +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. impl Add for DateTime { type Output = DateTime; @@ -1258,6 +1303,19 @@ impl Add for DateTime { } } +/// Add `Months` to `DateTime`. +/// +/// The result will be clamped to valid days in the resulting month, see `checked_add_months` for +/// details. +/// +/// # Panics +/// +/// Panics if: +/// - The resulting date would be out of range. +/// - The local time at the resulting date does not exist or is ambiguous, for example during a +/// daylight saving time transition. +/// +/// Strongly consider using [`DateTime::checked_add_months`] to get an `Option` instead. impl Add for DateTime { type Output = DateTime; @@ -1266,6 +1324,18 @@ impl Add for DateTime { } } +/// Subtract `chrono::Duration` from `DateTime`. +/// +/// This is the same as the addition with a negated `Duration`. +/// +/// As a part of Chrono's [leap second handling] the subtraction assumes that **there is no leap +/// second ever**, except when the `DateTime` itself represents a leap second in which case +/// the assumption becomes that **there is exactly a single leap second ever**. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using [`DateTime::checked_sub_signed`] to get an `Option` instead. impl Sub for DateTime { type Output = DateTime; @@ -1275,6 +1345,16 @@ impl Sub for DateTime { } } +/// Subtract `std::time::Duration` from `DateTime`. +/// +/// As a part of Chrono's [leap second handling] the subtraction assumes that **there is no leap +/// second ever**, except when the `DateTime` itself represents a leap second in which case +/// the assumption becomes that **there is exactly a single leap second ever**. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using [`DateTime::checked_sub_signed`] to get an `Option` instead. impl Sub for DateTime { type Output = DateTime; @@ -1286,6 +1366,18 @@ impl Sub for DateTime { } } +/// Subtract-assign `chrono::Duration` from `DateTime`. +/// +/// This is the same as the addition with a negated `Duration`. +/// +/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap +/// second ever**, except when the `DateTime` itself represents a leap second in which case +/// the assumption becomes that **there is exactly a single leap second ever**. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using [`DateTime::checked_sub_signed`] to get an `Option` instead. impl SubAssign for DateTime { #[inline] fn sub_assign(&mut self, rhs: OldDuration) { @@ -1296,6 +1388,16 @@ impl SubAssign for DateTime { } } +/// Subtract-assign `std::time::Duration` from `DateTime`. +/// +/// As a part of Chrono's [leap second handling], the addition assumes that **there is no leap +/// second ever**, except when the `DateTime` itself represents a leap second in which case +/// the assumption becomes that **there is exactly a single leap second ever**. +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. +/// Consider using [`DateTime::checked_sub_signed`] to get an `Option` instead. impl SubAssign for DateTime { #[inline] fn sub_assign(&mut self, rhs: Duration) { @@ -1305,6 +1407,11 @@ impl SubAssign for DateTime { } } +/// Subtract `FixedOffset` from the datetime value of `DateTime` (offset remains unchanged). +/// +/// # Panics +/// +/// Panics if the resulting date would be out of range. impl Sub for DateTime { type Output = DateTime; @@ -1316,6 +1423,19 @@ impl Sub for DateTime { } } +/// Subtract `Months` from `DateTime`. +/// +/// The result will be clamped to valid days in the resulting month, see +/// [`DateTime::checked_sub_months`] for details. +/// +/// # Panics +/// +/// Panics if: +/// - The resulting date would be out of range. +/// - The local time at the resulting date does not exist or is ambiguous, for example during a +/// daylight saving time transition. +/// +/// Strongly consider using [`DateTime::checked_sub_months`] to get an `Option` instead. impl Sub for DateTime { type Output = DateTime; @@ -1342,6 +1462,16 @@ impl Sub<&DateTime> for DateTime { } } +/// Add `Days` to `NaiveDateTime`. +/// +/// # Panics +/// +/// Panics if: +/// - The resulting date would be out of range. +/// - The local time at the resulting date does not exist or is ambiguous, for example during a +/// daylight saving time transition. +/// +/// Strongly consider using `DateTime::checked_sub_days` to get an `Option` instead. impl Add for DateTime { type Output = DateTime; @@ -1350,6 +1480,16 @@ impl Add for DateTime { } } +/// Subtract `Days` from `DateTime`. +/// +/// # Panics +/// +/// Panics if: +/// - The resulting date would be out of range. +/// - The local time at the resulting date does not exist or is ambiguous, for example during a +/// daylight saving time transition. +/// +/// Strongly consider using `DateTime::checked_sub_days` to get an `Option` instead. impl Sub for DateTime { type Output = DateTime;