Skip to content

Commit

Permalink
Move Add and Sub impls for Fixedoffset to their output type mod…
Browse files Browse the repository at this point in the history
…ules
  • Loading branch information
pitdicker committed Sep 8, 2023
1 parent 8577d6f commit a67f5bb
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 74 deletions.
28 changes: 28 additions & 0 deletions src/datetime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,25 @@ impl<Tz: TimeZone> AddAssign<Duration> for DateTime<Tz> {
}
}

fn add_with_leapsecond<T>(lhs: &T, rhs: i32) -> T
where
T: Timelike + Add<OldDuration, Output = T>,
{
// extract and temporarily remove the fractional part and later recover it
let nanos = lhs.nanosecond();
let lhs = lhs.with_nanosecond(0).unwrap();
(lhs + OldDuration::seconds(i64::from(rhs))).with_nanosecond(nanos).unwrap()
}

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

#[inline]
fn add(self, rhs: FixedOffset) -> DateTime<Tz> {
add_with_leapsecond(&self, rhs.local_minus_utc())
}
}

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

Expand Down Expand Up @@ -1213,6 +1232,15 @@ impl<Tz: TimeZone> SubAssign<Duration> for DateTime<Tz> {
}
}

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

#[inline]
fn sub(self, rhs: FixedOffset) -> DateTime<Tz> {
add_with_leapsecond(&self, -rhs.local_minus_utc())
}
}

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

Expand Down
18 changes: 18 additions & 0 deletions src/naive/datetime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1563,6 +1563,15 @@ impl AddAssign<Duration> for NaiveDateTime {
}
}

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

#[inline]
fn add(self, rhs: FixedOffset) -> NaiveDateTime {
self.checked_add_offset(rhs).unwrap()
}
}

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

Expand Down Expand Up @@ -1690,6 +1699,15 @@ impl SubAssign<Duration> for NaiveDateTime {
}
}

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

#[inline]
fn sub(self, rhs: FixedOffset) -> NaiveDateTime {
self.checked_sub_offset(rhs).unwrap()
}
}

/// A subtraction of Months from `NaiveDateTime` clamped to valid days in resulting month.
///
/// # Panics
Expand Down
18 changes: 18 additions & 0 deletions src/naive/time/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1157,6 +1157,15 @@ impl AddAssign<Duration> for NaiveTime {
}
}

impl Add<FixedOffset> for NaiveTime {
type Output = NaiveTime;

#[inline]
fn add(self, rhs: FixedOffset) -> NaiveTime {
self.overflowing_add_offset(rhs).0
}
}

/// 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 @@ -1239,6 +1248,15 @@ impl SubAssign<Duration> for NaiveTime {
}
}

impl Sub<FixedOffset> for NaiveTime {
type Output = NaiveTime;

#[inline]
fn sub(self, rhs: FixedOffset) -> NaiveTime {
self.overflowing_sub_offset(rhs).0
}
}

/// Subtracts another `NaiveTime` from the current time.
/// Returns a `Duration` within +/- 1 day.
/// This does not overflow or underflow at all.
Expand Down
76 changes: 2 additions & 74 deletions src/offset/fixed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,14 @@
//! The time zone which has a fixed offset from UTC.

use core::fmt;
use core::ops::{Add, Sub};
use core::str::FromStr;

#[cfg(feature = "rkyv")]
use rkyv::{Archive, Deserialize, Serialize};

use super::{LocalResult, Offset, TimeZone};
use crate::duration::Duration as OldDuration;
use crate::format::{scan, OUT_OF_RANGE};
use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime};
use crate::{DateTime, ParseError, Timelike};
use crate::format::{scan, ParseError, OUT_OF_RANGE};
use crate::naive::{NaiveDate, NaiveDateTime};

/// The time zone with fixed offset, from UTC-23:59:59 to UTC+23:59:59.
///
Expand Down Expand Up @@ -183,75 +180,6 @@ impl arbitrary::Arbitrary<'_> for FixedOffset {
}
}

// addition or subtraction of FixedOffset to/from Timelike values is the same as
// adding or subtracting the offset's local_minus_utc value
// but keep keeps the leap second information.
// this should be implemented more efficiently, but for the time being, this is generic right now.

fn add_with_leapsecond<T>(lhs: &T, rhs: i32) -> T
where
T: Timelike + Add<OldDuration, Output = T>,
{
// extract and temporarily remove the fractional part and later recover it
let nanos = lhs.nanosecond();
let lhs = lhs.with_nanosecond(0).unwrap();
(lhs + OldDuration::seconds(i64::from(rhs))).with_nanosecond(nanos).unwrap()
}

impl Add<FixedOffset> for NaiveTime {
type Output = NaiveTime;

#[inline]
fn add(self, rhs: FixedOffset) -> NaiveTime {
self.overflowing_add_offset(rhs).0
}
}

impl Sub<FixedOffset> for NaiveTime {
type Output = NaiveTime;

#[inline]
fn sub(self, rhs: FixedOffset) -> NaiveTime {
self.overflowing_sub_offset(rhs).0
}
}

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

#[inline]
fn add(self, rhs: FixedOffset) -> NaiveDateTime {
self.checked_add_offset(rhs).unwrap()
}
}

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

#[inline]
fn sub(self, rhs: FixedOffset) -> NaiveDateTime {
self.checked_sub_offset(rhs).unwrap()
}
}

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

#[inline]
fn add(self, rhs: FixedOffset) -> DateTime<Tz> {
add_with_leapsecond(&self, rhs.local_minus_utc)
}
}

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

#[inline]
fn sub(self, rhs: FixedOffset) -> DateTime<Tz> {
add_with_leapsecond(&self, -rhs.local_minus_utc)
}
}

#[cfg(test)]
mod tests {
use super::FixedOffset;
Expand Down

0 comments on commit a67f5bb

Please sign in to comment.