From 16d8a3c79a5b2d47193af3ae91af51b10d538be9 Mon Sep 17 00:00:00 2001 From: MrGunflame Date: Mon, 23 May 2022 22:58:54 +0200 Subject: [PATCH 1/6] Impl AddAssign and SubAssign for Date and DateTime --- src/date.rs | 16 +++++++++++++++- src/datetime/mod.rs | 16 +++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/date.rs b/src/date.rs index 0c9b1eef4f..d2d5fed3f9 100644 --- a/src/date.rs +++ b/src/date.rs @@ -6,7 +6,7 @@ #[cfg(any(feature = "alloc", feature = "std", test))] use core::borrow::Borrow; use core::cmp::Ordering; -use core::ops::{Add, Sub}; +use core::ops::{Add, AddAssign, Sub, SubAssign}; use core::{fmt, hash}; #[cfg(feature = "rkyv")] @@ -479,6 +479,13 @@ impl Add for Date { } } +impl AddAssign for Date { + #[inline] + fn add_assign(&mut self, rhs: OldDuration) { + self.date += rhs; + } +} + impl Sub for Date { type Output = Date; @@ -488,6 +495,13 @@ impl Sub for Date { } } +impl SubAssign for Date { + #[inline] + fn sub_assign(&mut self, rhs: OldDuration) { + self.date -= rhs; + } +} + impl Sub> for Date { type Output = OldDuration; diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index cc902646e9..170ba044b6 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -11,7 +11,7 @@ use alloc::string::{String, ToString}; #[cfg(any(feature = "alloc", feature = "std", test))] use core::borrow::Borrow; use core::cmp::Ordering; -use core::ops::{Add, Sub}; +use core::ops::{Add, AddAssign, Sub, SubAssign}; use core::{fmt, hash, str}; #[cfg(feature = "std")] use std::string::ToString; @@ -852,6 +852,13 @@ impl Add for DateTime { } } +impl AddAssign for DateTime { + #[inline] + fn add_assign(&mut self, rhs: OldDuration) { + self.datetime += rhs; + } +} + impl Sub for DateTime { type Output = DateTime; @@ -861,6 +868,13 @@ impl Sub for DateTime { } } +impl SubAssign for DateTime { + #[inline] + fn sub_assign(&mut self, rhs: OldDuration) { + self.datetime -= rhs; + } +} + impl Sub> for DateTime { type Output = OldDuration; From cc0c268b47c7ec38ca3aefb31c2ec7bc43f529ce Mon Sep 17 00:00:00 2001 From: MrGunflame Date: Wed, 25 May 2022 03:46:47 +0200 Subject: [PATCH 2/6] Add tests for AddAssign and SubAssign --- src/datetime/tests.rs | 44 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index fbf959e10d..3ccadae0b3 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -426,3 +426,47 @@ fn test_years_elapsed() { let future = Utc::today() + Duration::weeks(12); assert_eq!(Utc::today().years_since(future), None); } + +#[test] +fn test_datetime_add_assign() { + let naivedatetime = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0); + let datetime = DateTime::::from_utc(naivedatetime, Utc); + let mut datetime_add = datetime; + + datetime_add += Duration::seconds(60); + assert_eq!(datetime_add, datetime + Duration::seconds(60)); + + let timezone = FixedOffset::east(60 * 60); + let datetime = datetime.with_timezone(&timezone); + let datetime_add = datetime_add.with_timezone(&timezone); + + assert_eq!(datetime_add, datetime + Duration::seconds(60)); + + let timezone = FixedOffset::west(2 * 60 * 60); + let datetime = datetime.with_timezone(&timezone); + let datetime_add = datetime_add.with_timezone(&timezone); + + assert_eq!(datetime_add, datetime + Duration::seconds(60)); +} + +#[test] +fn test_datetime_sub_assign() { + let naivedatetime = NaiveDate::from_ymd(2000, 1, 1).and_hms(12, 0, 0); + let datetime = DateTime::::from_utc(naivedatetime, Utc); + let mut datetime_sub = datetime; + + datetime_sub -= Duration::minutes(90); + assert_eq!(datetime_sub, datetime - Duration::minutes(90)); + + let timezone = FixedOffset::east(60 * 60); + let datetime = datetime.with_timezone(&timezone); + let datetime_sub = datetime_sub.with_timezone(&timezone); + + assert_eq!(datetime_sub, datetime - Duration::minutes(90)); + + let timezone = FixedOffset::west(2 * 60 * 60); + let datetime = datetime.with_timezone(&timezone); + let datetime_sub = datetime_sub.with_timezone(&timezone); + + assert_eq!(datetime_sub, datetime - Duration::minutes(90)); +} From 06cb7d2ba87648ab4673fc1b6a2f9a0856e35de8 Mon Sep 17 00:00:00 2001 From: MrGunflame Date: Wed, 25 May 2022 04:15:05 +0200 Subject: [PATCH 3/6] Add tests for AddAssign and SubAssign on Date --- src/date.rs | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/src/date.rs b/src/date.rs index d2d5fed3f9..025641d088 100644 --- a/src/date.rs +++ b/src/date.rs @@ -528,7 +528,10 @@ where #[cfg(test)] mod tests { - use crate::{Duration, Utc}; + use super::Date; + + use crate::oldtime::Duration; + use crate::{FixedOffset, NaiveDate, Utc}; #[test] #[cfg(feature = "clock")] @@ -547,4 +550,48 @@ mod tests { let future = Utc::today() + Duration::weeks(12); assert_eq!(Utc::today().years_since(future), None); } + + #[test] + fn test_date_add_assign() { + let naivedate = NaiveDate::from_ymd(2000, 1, 1); + let date = Date::::from_utc(naivedate, Utc); + let mut date_add = date; + + date_add += Duration::days(5); + assert_eq!(date_add, date + Duration::days(5)); + + let timezone = FixedOffset::east(60 * 60); + let date = date.with_timezone(&timezone); + let date_add = date_add.with_timezone(&timezone); + + assert_eq!(date_add, date + Duration::days(5)); + + let timezone = FixedOffset::west(2 * 60 * 60); + let date = date.with_timezone(&timezone); + let date_add = date_add.with_timezone(&timezone); + + assert_eq!(date_add, date + Duration::days(5)); + } + + #[test] + fn test_date_sub_assign() { + let naivedate = NaiveDate::from_ymd(2000, 1, 1); + let date = Date::::from_utc(naivedate, Utc); + let mut date_sub = date; + + date_sub -= Duration::days(5); + assert_eq!(date_sub, date - Duration::days(5)); + + let timezone = FixedOffset::east(60 * 60); + let date = date.with_timezone(&timezone); + let date_sub = date_sub.with_timezone(&timezone); + + assert_eq!(date_sub, date - Duration::days(5)); + + let timezone = FixedOffset::west(2 * 60 * 60); + let date = date.with_timezone(&timezone); + let date_sub = date_sub.with_timezone(&timezone); + + assert_eq!(date_sub, date - Duration::days(5)); + } } From 63c0c17b53e696200c7583adcabdd3339682c387 Mon Sep 17 00:00:00 2001 From: MrGunflame Date: Sat, 4 Jun 2022 23:44:01 +0200 Subject: [PATCH 4/6] AddAssign/SubAssign impls mimic their checked methods --- src/date.rs | 18 +++++++++++++++--- src/datetime/mod.rs | 10 ++++++++-- src/datetime/tests.rs | 12 ++++++++++++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/date.rs b/src/date.rs index 025641d088..b400159410 100644 --- a/src/date.rs +++ b/src/date.rs @@ -482,7 +482,7 @@ impl Add for Date { impl AddAssign for Date { #[inline] fn add_assign(&mut self, rhs: OldDuration) { - self.date += rhs; + self.date = self.date.checked_add_signed(rhs).expect("`Date + Duration` overflowed"); } } @@ -498,7 +498,7 @@ impl Sub for Date { impl SubAssign for Date { #[inline] fn sub_assign(&mut self, rhs: OldDuration) { - self.date -= rhs; + self.date = self.date.checked_sub_signed(rhs).expect("`Date - Duration` overflowed"); } } @@ -531,7 +531,7 @@ mod tests { use super::Date; use crate::oldtime::Duration; - use crate::{FixedOffset, NaiveDate, Utc}; + use crate::{FixedOffset, Local, NaiveDate, TimeZone, Utc}; #[test] #[cfg(feature = "clock")] @@ -571,6 +571,12 @@ mod tests { let date_add = date_add.with_timezone(&timezone); assert_eq!(date_add, date + Duration::days(5)); + + let date = Local.from_utc_date(&naivedate); + let mut date_add = date; + + date_add += Duration::days(5); + assert_eq!(date_add, date + Duration::days(5)); } #[test] @@ -593,5 +599,11 @@ mod tests { let date_sub = date_sub.with_timezone(&timezone); assert_eq!(date_sub, date - Duration::days(5)); + + let date = Local.from_utc_date(&naivedate); + let mut date_sub = date; + + date_sub -= Duration::days(5); + assert_eq!(date_sub, date - Duration::days(5)); } } diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index 170ba044b6..6af2abb64a 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -855,7 +855,10 @@ impl Add for DateTime { impl AddAssign for DateTime { #[inline] fn add_assign(&mut self, rhs: OldDuration) { - self.datetime += rhs; + let datetime = + self.datetime.checked_add_signed(rhs).expect("`DateTime + Duration` overflowed"); + let tz = self.timezone(); + *self = tz.from_utc_datetime(&datetime); } } @@ -871,7 +874,10 @@ impl Sub for DateTime { impl SubAssign for DateTime { #[inline] fn sub_assign(&mut self, rhs: OldDuration) { - self.datetime -= rhs; + let datetime = + self.datetime.checked_sub_signed(rhs).expect("`DateTime - Duration` overflowed"); + let tz = self.timezone(); + *self = tz.from_utc_datetime(&datetime) } } diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index 3ccadae0b3..2c5bc98cbc 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -447,6 +447,12 @@ fn test_datetime_add_assign() { let datetime_add = datetime_add.with_timezone(&timezone); assert_eq!(datetime_add, datetime + Duration::seconds(60)); + + let datetime = Local.from_utc_datetime(&naivedatetime); + let mut datetime_add = datetime; + + datetime_add += Duration::seconds(60); + assert_eq!(datetime_add, datetime + Duration::seconds(60)); } #[test] @@ -469,4 +475,10 @@ fn test_datetime_sub_assign() { let datetime_sub = datetime_sub.with_timezone(&timezone); assert_eq!(datetime_sub, datetime - Duration::minutes(90)); + + let datetime = Local.from_utc_datetime(&naivedatetime); + let mut datetime_sub = datetime; + + datetime_sub -= Duration::minutes(90); + assert_eq!(datetime_sub, datetime - Duration::minutes(90)); } From 5156e0b375a95c76af2ca3acd01a1c5967faaa92 Mon Sep 17 00:00:00 2001 From: MrGunflame Date: Wed, 8 Jun 2022 23:14:21 +0200 Subject: [PATCH 5/6] Gate tests for Local timezone behind clock feature --- src/date.rs | 17 ++++++++++++++++- src/datetime/tests.rs | 12 ++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/date.rs b/src/date.rs index b400159410..4f08c33887 100644 --- a/src/date.rs +++ b/src/date.rs @@ -531,7 +531,10 @@ mod tests { use super::Date; use crate::oldtime::Duration; - use crate::{FixedOffset, Local, NaiveDate, TimeZone, Utc}; + use crate::{FixedOffset, NaiveDate, Utc}; + + #[cfg(feature = "clock")] + use crate::offset::{Local, TimeZone}; #[test] #[cfg(feature = "clock")] @@ -571,6 +574,12 @@ mod tests { let date_add = date_add.with_timezone(&timezone); assert_eq!(date_add, date + Duration::days(5)); + } + + #[test] + #[cfg(feature = "clock")] + fn test_date_add_assign_local() { + let naivedate = NaiveDate::from_ymd(2000, 1, 1); let date = Local.from_utc_date(&naivedate); let mut date_add = date; @@ -599,6 +608,12 @@ mod tests { let date_sub = date_sub.with_timezone(&timezone); assert_eq!(date_sub, date - Duration::days(5)); + } + + #[test] + #[cfg(feature = "clock")] + fn test_date_sub_assign_local() { + let naivedate = NaiveDate::from_ymd(2000, 1, 1); let date = Local.from_utc_date(&naivedate); let mut date_sub = date; diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index 2c5bc98cbc..6675879be4 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -447,6 +447,12 @@ fn test_datetime_add_assign() { let datetime_add = datetime_add.with_timezone(&timezone); assert_eq!(datetime_add, datetime + Duration::seconds(60)); +} + +#[test] +#[cfg(feature = "clock")] +fn test_datetime_add_assign_local() { + let naivedatetime = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0); let datetime = Local.from_utc_datetime(&naivedatetime); let mut datetime_add = datetime; @@ -475,6 +481,12 @@ fn test_datetime_sub_assign() { let datetime_sub = datetime_sub.with_timezone(&timezone); assert_eq!(datetime_sub, datetime - Duration::minutes(90)); +} + +#[test] +#[cfg(feature = "clock")] +fn test_datetime_sub_assign_local() { + let naivedatetime = NaiveDate::from_ymd(2000, 1, 1).and_hms(12, 0, 0); let datetime = Local.from_utc_datetime(&naivedatetime); let mut datetime_sub = datetime; From 1fbf37a066fe0e5a6826afd7f70c963ad9d731cd Mon Sep 17 00:00:00 2001 From: Eric Sheppard Date: Thu, 9 Jun 2022 20:16:29 +1000 Subject: [PATCH 6/6] make sure add/sub_assign_local tests cross a DST transition if relevant --- src/datetime/tests.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index 6675879be4..d9b11757c8 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -452,13 +452,16 @@ fn test_datetime_add_assign() { #[test] #[cfg(feature = "clock")] fn test_datetime_add_assign_local() { - let naivedatetime = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0); + let naivedatetime = NaiveDate::from_ymd(2022, 1, 1).and_hms(0, 0, 0); let datetime = Local.from_utc_datetime(&naivedatetime); - let mut datetime_add = datetime; + let mut datetime_add = Local.from_utc_datetime(&naivedatetime); - datetime_add += Duration::seconds(60); - assert_eq!(datetime_add, datetime + Duration::seconds(60)); + // ensure we cross a DST transition + for i in 1..=365 { + datetime_add += Duration::days(1); + assert_eq!(datetime_add, datetime + Duration::days(i)) + } } #[test] @@ -486,11 +489,14 @@ fn test_datetime_sub_assign() { #[test] #[cfg(feature = "clock")] fn test_datetime_sub_assign_local() { - let naivedatetime = NaiveDate::from_ymd(2000, 1, 1).and_hms(12, 0, 0); + let naivedatetime = NaiveDate::from_ymd(2022, 1, 1).and_hms(0, 0, 0); let datetime = Local.from_utc_datetime(&naivedatetime); - let mut datetime_sub = datetime; + let mut datetime_sub = Local.from_utc_datetime(&naivedatetime); - datetime_sub -= Duration::minutes(90); - assert_eq!(datetime_sub, datetime - Duration::minutes(90)); + // ensure we cross a DST transition + for i in 1..=365 { + datetime_sub -= Duration::days(1); + assert_eq!(datetime_sub, datetime - Duration::days(i)) + } }