From cf2673d4d4bc8d6b96f4488847d8c2b3c3545010 Mon Sep 17 00:00:00 2001 From: Botahamec Date: Mon, 21 Mar 2022 22:00:30 -0400 Subject: Add seconds or nanoseconds to DateTime --- src/datetime.rs | 32 +++++++++++++++++++++++++++++++- src/month.rs | 2 +- src/tai.rs | 6 +++--- src/timezone.rs | 8 ++++---- 4 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/datetime.rs b/src/datetime.rs index 9332de1..49506e3 100644 --- a/src/datetime.rs +++ b/src/datetime.rs @@ -30,6 +30,16 @@ impl DateTime { } } + pub fn from_local(local_datetime: NaiveDateTime, timezone: Tz) -> Result { + let offset = timezone.offset_from_local_naive(local_datetime)?; + // TODO overflow + let utc_datetime = local_datetime + .add_seconds_overflowing(-offset.seconds_ahead() as i64) + .0; + + Ok(Self::from_utc(utc_datetime, timezone)) + } + pub fn offset(&self) -> UtcOffset { let utc = self.as_utc(); self.timezone.utc_offset(utc) @@ -69,6 +79,26 @@ impl DateTime { pub fn tai_timestamp(&self) -> UnixTimestamp { self.as_tai().to_naive_overflowing().0.timestamp() } + + #[must_use] + pub fn add_seconds_overflowing(self, seconds: i64) -> (Self, bool) { + let (tai_timestamp, overflow) = self.tai_timestamp().add_seconds_overflowing(seconds); + let tai_naive_dt = NaiveDateTime::from_timestamp(tai_timestamp); + let tai_dt = DateTime::from_local(tai_naive_dt, Tai).unwrap(); + + (tai_dt.into_timezone(self.timezone), overflow) + } + + #[must_use] + pub fn add_nanoseconds_overflowing(self, nanoseconds: i64) -> (Self, bool) { + let (tai_timestamp, overflow) = self + .tai_timestamp() + .add_nanoseconds_overflowing(nanoseconds); + let tai_naive_dt = NaiveDateTime::from_timestamp(tai_timestamp); + let tai_dt = DateTime::from_local(tai_naive_dt, Tai).unwrap(); + + (tai_dt.into_timezone(self.timezone), overflow) + } } impl NaiveDateTime { @@ -285,7 +315,7 @@ impl PartialEq> for DateTime } impl Hash for DateTime { - fn hash(&self, state: &mut H) { + fn hash(&self, state: &mut H) { self.utc_datetime.hash(state); } } diff --git a/src/month.rs b/src/month.rs index 1419717..faf891d 100644 --- a/src/month.rs +++ b/src/month.rs @@ -405,7 +405,7 @@ impl Month { let zero_indexed_month = zero_indexed_num % 12; let month = match Self::from_u8((zero_indexed_month as u8) + 1) { Some(month) => month, - None => unsafe { std::hint::unreachable_unchecked() }, + None => unsafe { core::hint::unreachable_unchecked() }, }; (month, wraps) diff --git a/src/tai.rs b/src/tai.rs index 8dd91d2..015e70e 100644 --- a/src/tai.rs +++ b/src/tai.rs @@ -83,7 +83,7 @@ impl TimeZone for Tai { } // TODO optimize - fn offset_from_local_time(&self, date_time: NaiveDateTime) -> Result { + fn offset_from_local_naive(&self, date_time: NaiveDateTime) -> Result { // TAI times cannot have leap seconds if date_time.second() == 60 { return Err(UnexpectedLeapSecond { @@ -120,7 +120,7 @@ mod tests { #[test] fn test_conversion_no_leap_seconds() { let offset = unsafe { - Tai.offset_from_local_time(NaiveDateTime::new( + Tai.offset_from_local_naive(NaiveDateTime::new( Date::from_ymd_unchecked(2000.into(), Month::January, 1), Time::from_hms_unchecked(0, 0, 0), )) @@ -134,7 +134,7 @@ mod tests { fn test_conversion_one_leap_second() { add_leap_second(unsafe { Date::from_ymd_unchecked(2000.into(), Month::January, 1) }); let offset = unsafe { - Tai.offset_from_local_time(NaiveDateTime::new( + Tai.offset_from_local_naive(NaiveDateTime::new( Date::from_ymd_unchecked(2000.into(), Month::January, 2), Time::from_hms_unchecked(0, 0, 0), )) diff --git a/src/timezone.rs b/src/timezone.rs index f0096c6..eb539fb 100644 --- a/src/timezone.rs +++ b/src/timezone.rs @@ -5,7 +5,7 @@ use core::fmt::Display; /// A type that can be used to represent a `TimeZone` pub trait TimeZone: Sized + Eq + Display { /// The error to return in case of a failure to convert the local time to UTC - type Err; + type Err: core::fmt::Debug; /// Given the time in the UTC timezone, determine the `UtcOffset` fn utc_offset(&self, date_time: DateTime) -> UtcOffset; @@ -16,7 +16,7 @@ pub trait TimeZone: Sized + Eq + Display { /// /// This returns an Err if the given `NaiveDateTime` cannot exist in this timezone. /// For example, the time may have been skipped because of daylight savings time. - fn offset_from_local_time(&self, date_time: NaiveDateTime) -> Result; + fn offset_from_local_naive(&self, date_time: NaiveDateTime) -> Result; } #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] @@ -30,7 +30,7 @@ impl TimeZone for Utc { UtcOffset::UTC } - fn offset_from_local_time(&self, _: NaiveDateTime) -> Result { + fn offset_from_local_naive(&self, _: NaiveDateTime) -> Result { Ok(UtcOffset::UTC) } } @@ -121,7 +121,7 @@ impl TimeZone for UtcOffset { *self } - fn offset_from_local_time(&self, _: NaiveDateTime) -> Result { + fn offset_from_local_naive(&self, _: NaiveDateTime) -> Result { Ok(*self) } } -- cgit v1.2.3