Move Add and Sub impls for Fixedoffset to datetime modules

This commit is contained in:
Paul Dicker 2023-05-19 14:51:22 +02:00 committed by Paul Dicker
parent c836a1f93c
commit b1473c4e39
2 changed files with 29 additions and 37 deletions

View File

@ -1247,6 +1247,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>;
@ -1294,6 +1313,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>;

View File

@ -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::format::{scan, ParseError, OUT_OF_RANGE};
use crate::naive::{NaiveDate, NaiveDateTime};
use crate::{DateTime, ParseError, Timelike};
/// The time zone with fixed offset, from UTC-23:59:59 to UTC+23:59:59.
///
@ -184,39 +181,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<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;