Skip to content

Commit

Permalink
Implement operations for core::time::Duration
Browse files Browse the repository at this point in the history
  • Loading branch information
djc committed Aug 29, 2023
1 parent e602b4c commit a9fb2cc
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 2 deletions.
43 changes: 41 additions & 2 deletions src/datetime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use core::borrow::Borrow;
use core::cmp::Ordering;
use core::fmt::Write;
use core::ops::{Add, AddAssign, Sub, SubAssign};
use core::time::Duration;
use core::{fmt, hash, str};
#[cfg(feature = "std")]
use std::time::{SystemTime, UNIX_EPOCH};
Expand Down Expand Up @@ -1131,6 +1132,17 @@ impl<Tz: TimeZone> Add<OldDuration> for DateTime<Tz> {
}
}

impl<Tz: TimeZone> Add<Duration> for DateTime<Tz> {
type Output = DateTime<Tz>;

#[inline]
fn add(self, rhs: Duration) -> DateTime<Tz> {
let rhs = OldDuration::from_std(rhs)
.expect("overflow converting from core::time::Duration to chrono::Duration");
self.checked_add_signed(rhs).expect("`DateTime + Duration` overflowed")
}
}

impl<Tz: TimeZone> AddAssign<OldDuration> for DateTime<Tz> {
#[inline]
fn add_assign(&mut self, rhs: OldDuration) {
Expand All @@ -1141,6 +1153,15 @@ impl<Tz: TimeZone> AddAssign<OldDuration> for DateTime<Tz> {
}
}

impl<Tz: TimeZone> AddAssign<Duration> for DateTime<Tz> {
#[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;
}
}

impl<Tz: TimeZone> Add<Months> for DateTime<Tz> {
type Output = DateTime<Tz>;

Expand All @@ -1158,6 +1179,17 @@ impl<Tz: TimeZone> Sub<OldDuration> for DateTime<Tz> {
}
}

impl<Tz: TimeZone> Sub<Duration> for DateTime<Tz> {
type Output = DateTime<Tz>;

#[inline]
fn sub(self, rhs: Duration) -> DateTime<Tz> {
let rhs = OldDuration::from_std(rhs)
.expect("overflow converting from core::time::Duration to chrono::Duration");
self.checked_sub_signed(rhs).expect("`DateTime - Duration` overflowed")
}
}

impl<Tz: TimeZone> SubAssign<OldDuration> for DateTime<Tz> {
#[inline]
fn sub_assign(&mut self, rhs: OldDuration) {
Expand All @@ -1168,6 +1200,15 @@ impl<Tz: TimeZone> SubAssign<OldDuration> for DateTime<Tz> {
}
}

impl<Tz: TimeZone> SubAssign<Duration> for DateTime<Tz> {
#[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;
}
}

impl<Tz: TimeZone> Sub<Months> for DateTime<Tz> {
type Output = DateTime<Tz>;

Expand Down Expand Up @@ -1305,8 +1346,6 @@ impl From<SystemTime> for DateTime<Local> {
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl<Tz: TimeZone> From<DateTime<Tz>> for SystemTime {
fn from(dt: DateTime<Tz>) -> SystemTime {
use std::time::Duration;

let sec = dt.timestamp();
let nsec = dt.timestamp_subsec_nanos();
if sec < 0 {
Expand Down
21 changes: 21 additions & 0 deletions src/datetime/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1362,6 +1362,27 @@ fn test_datetime_sub_assign_local() {
}
}

#[test]
fn test_core_duration_ops() {
use core::time::Duration;

let mut utc_dt = Utc.with_ymd_and_hms(2023, 8, 29, 11, 34, 12).unwrap();
let same = utc_dt + Duration::ZERO;
assert_eq!(utc_dt, same);

utc_dt += Duration::new(3600, 0);
assert_eq!(utc_dt, Utc.with_ymd_and_hms(2023, 8, 29, 12, 34, 12).unwrap());
}

#[test]
#[should_panic]
fn test_core_duration_max() {
use core::time::Duration;

let mut utc_dt = Utc.with_ymd_and_hms(2023, 8, 29, 11, 34, 12).unwrap();
utc_dt += Duration::MAX;
}

#[test]
#[cfg(all(target_os = "windows", feature = "clock"))]
fn test_from_naive_date_time_windows() {
Expand Down
37 changes: 37 additions & 0 deletions src/naive/datetime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use core::borrow::Borrow;
use core::fmt::Write;
use core::ops::{Add, AddAssign, Sub, SubAssign};
use core::time::Duration;
use core::{fmt, str};

#[cfg(feature = "rkyv")]
Expand Down Expand Up @@ -1516,13 +1517,31 @@ impl Add<OldDuration> for NaiveDateTime {
}
}

impl Add<Duration> for NaiveDateTime {
type Output = NaiveDateTime;

#[inline]
fn add(self, rhs: Duration) -> NaiveDateTime {
let rhs = OldDuration::from_std(rhs)
.expect("overflow converting from core::time::Duration to chrono::Duration");
self.checked_add_signed(rhs).expect("`NaiveDateTime + Duration` overflowed")
}
}

impl AddAssign<OldDuration> for NaiveDateTime {
#[inline]
fn add_assign(&mut self, rhs: OldDuration) {
*self = self.add(rhs);
}
}

impl AddAssign<Duration> for NaiveDateTime {
#[inline]
fn add_assign(&mut self, rhs: Duration) {
*self = self.add(rhs);
}
}

impl Add<Months> for NaiveDateTime {
type Output = NaiveDateTime;

Expand Down Expand Up @@ -1625,13 +1644,31 @@ impl Sub<OldDuration> for NaiveDateTime {
}
}

impl Sub<Duration> for NaiveDateTime {
type Output = NaiveDateTime;

#[inline]
fn sub(self, rhs: Duration) -> NaiveDateTime {
let rhs = OldDuration::from_std(rhs)
.expect("overflow converting from core::time::Duration to chrono::Duration");
self.checked_sub_signed(rhs).expect("`NaiveDateTime - Duration` overflowed")
}
}

impl SubAssign<OldDuration> for NaiveDateTime {
#[inline]
fn sub_assign(&mut self, rhs: OldDuration) {
*self = self.sub(rhs);
}
}

impl SubAssign<Duration> for NaiveDateTime {
#[inline]
fn sub_assign(&mut self, rhs: Duration) {
*self = self.sub(rhs);
}
}

/// A subtraction of Months from `NaiveDateTime` clamped to valid days in resulting month.
///
/// # Panics
Expand Down
21 changes: 21 additions & 0 deletions src/naive/datetime/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,27 @@ fn test_datetime_subassignment() {
assert_eq!(date, ymdhms(1997, 9, 16, 23, 30, 10));
}

#[test]
fn test_core_duration_ops() {
use core::time::Duration;

let mut dt = NaiveDate::from_ymd_opt(2023, 8, 29).unwrap().and_hms_opt(11, 34, 12).unwrap();
let same = dt + Duration::ZERO;
assert_eq!(dt, same);

dt += Duration::new(3600, 0);
assert_eq!(dt, NaiveDate::from_ymd_opt(2023, 8, 29).unwrap().and_hms_opt(12, 34, 12).unwrap());
}

#[test]
#[should_panic]
fn test_core_duration_max() {
use core::time::Duration;

let mut utc_dt = NaiveDate::from_ymd_opt(2023, 8, 29).unwrap().and_hms_opt(11, 34, 12).unwrap();
utc_dt += Duration::MAX;
}

#[test]
fn test_datetime_timestamp() {
let to_timestamp = |y, m, d, h, n, s| {
Expand Down
41 changes: 41 additions & 0 deletions src/naive/time/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#[cfg(any(feature = "alloc", feature = "std"))]
use core::borrow::Borrow;
use core::ops::{Add, AddAssign, Sub, SubAssign};
use core::time::Duration;
use core::{fmt, str};

#[cfg(feature = "rkyv")]
Expand Down Expand Up @@ -1112,6 +1113,26 @@ impl AddAssign<OldDuration> for NaiveTime {
}
}

impl Add<Duration> for NaiveTime {
type Output = 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
}
}

impl AddAssign<Duration> 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;
}
}

/// 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`.
Expand Down Expand Up @@ -1174,6 +1195,26 @@ impl SubAssign<OldDuration> for NaiveTime {
}
}

impl Sub<Duration> for NaiveTime {
type Output = 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
}
}

impl SubAssign<Duration> 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;
}
}

/// Subtracts another `NaiveTime` from the current time.
/// Returns a `Duration` within +/- 1 day.
/// This does not overflow or underflow at all.
Expand Down
15 changes: 15 additions & 0 deletions src/naive/time/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,21 @@ fn test_time_sub() {
assert_eq!(hmsm(3, 5, 6, 1_800) + OldDuration::milliseconds(400), hmsm(3, 5, 7, 200));
}

#[test]
fn test_core_duration_ops() {
use core::time::Duration;

let mut t = NaiveTime::from_hms_opt(11, 34, 23).unwrap();
let same = t + Duration::ZERO;
assert_eq!(t, same);

t += Duration::new(3600, 0);
assert_eq!(t, NaiveTime::from_hms_opt(12, 34, 23).unwrap());

t -= Duration::new(7200, 0);
assert_eq!(t, NaiveTime::from_hms_opt(10, 34, 23).unwrap());
}

#[test]
fn test_time_fmt() {
assert_eq!(
Expand Down

0 comments on commit a9fb2cc

Please sign in to comment.