diff options
| author | Botahamec <botahamec@outlook.com> | 2022-03-18 14:57:13 -0400 |
|---|---|---|
| committer | Botahamec <botahamec@outlook.com> | 2022-03-18 14:57:13 -0400 |
| commit | db9f20681f90f206d393d2b06a6a8401515ff562 (patch) | |
| tree | 48c16c94a4bf0da27c7cde56a247703b7794600c /src/datetime.rs | |
| parent | e0e0a18a4bc873583e973d771669e88a92b20d92 (diff) | |
Addition methods for NaiveDateTime
Diffstat (limited to 'src/datetime.rs')
| -rw-r--r-- | src/datetime.rs | 108 |
1 files changed, 102 insertions, 6 deletions
diff --git a/src/datetime.rs b/src/datetime.rs index 9a43a4b..931d023 100644 --- a/src/datetime.rs +++ b/src/datetime.rs @@ -1,4 +1,5 @@ use crate::{ + date::{DayGreaterThanMaximumForMonthError, LeapDayNotInLeapYearError}, timezone::{Utc, UtcOffset}, Date, Month, Time, TimeZone, UnixTimestamp, Year, }; @@ -50,6 +51,22 @@ impl NaiveDateTime { Self { date, time } } + pub const fn from_timestamp(timestamp: UnixTimestamp) -> Self { + const UNIX_EPOCH_DAYS_AFTER_CE: i64 = Date::UNIX_EPOCH.days_after_common_era(); + let days_after_unix_epoch = timestamp.seconds_since_unix_epoch() / 86_400; + let days_after_ce = days_after_unix_epoch + UNIX_EPOCH_DAYS_AFTER_CE as i64; + let date = Date::from_days_after_common_era(days_after_ce); + let seconds_after_midnight = timestamp.seconds_since_unix_epoch() % 86_400; + let nanoseconds = timestamp.nanosecond(); + let time = Time::MIDNIGHT + .add_seconds_overflowing(seconds_after_midnight as isize) + .0 + .add_nanoseconds_overflowing(nanoseconds as isize) + .0; + + Self::new(date, time) + } + #[must_use] pub const fn date(self) -> Date { self.date @@ -106,19 +123,97 @@ impl NaiveDateTime { } #[must_use] - pub fn add_seconds_overflowing(self, seconds: i64) -> (Self, bool) { - let timestamp: UnixTimestamp = self.into(); + pub const fn timestamp(self) -> UnixTimestamp { + const UNIX_EPOCH_DAYS: i64 = Date::UNIX_EPOCH.days_after_common_era(); + // TODO don't require the .date() + let days = (self.date.days_after_common_era() - UNIX_EPOCH_DAYS) as i64; + let seconds = days * 86_400 + self.time().seconds_from_midnight() as i64; + let nanoseconds = self.nanosecond(); + + UnixTimestamp::new(seconds, nanoseconds) + } + + pub const fn add_years_overflowing( + self, + years: i16, + ) -> Result<(Self, bool), LeapDayNotInLeapYearError> { + let (date, overflow) = match self.date.add_years_overflowing(years) { + Ok(v) => v, + Err(e) => return Err(e), + }; + + Ok(( + Self { + date, + time: self.time, + }, + overflow, + )) + } + + pub const fn add_months_overflowing( + self, + months: i8, + ) -> Result<(Self, bool), DayGreaterThanMaximumForMonthError> { + let (date, overflow) = match self.date.add_months_overflowing(months) { + Ok(v) => v, + Err(e) => return Err(e), + }; + + Ok(( + Self { + date, + time: self.time, + }, + overflow, + )) + } + + #[must_use] + pub const fn add_days_overflowing(self, days: i64) -> (Self, bool) { + let (date, overflow) = self.date.add_days_overflowing(days); + + ( + Self { + date, + time: self.time, + }, + overflow, + ) + } + + #[must_use] + pub const fn add_hours_overflowing(self, hours: i64) -> (Self, bool) { + let timestamp: UnixTimestamp = self.timestamp(); + let (timestamp, overflow) = timestamp.add_hours_overflowing(hours); + let datetime: NaiveDateTime = Self::from_timestamp(timestamp); + + (datetime, overflow) + } + + #[must_use] + pub const fn add_minutes_overflowing(self, minutes: i64) -> (Self, bool) { + let timestamp: UnixTimestamp = self.timestamp(); + let (timestamp, overflow) = timestamp.add_minutes_overflowing(minutes); + let datetime: NaiveDateTime = Self::from_timestamp(timestamp); + + (datetime, overflow) + } + + #[must_use] + pub const fn add_seconds_overflowing(self, seconds: i64) -> (Self, bool) { + let timestamp: UnixTimestamp = self.timestamp(); let (timestamp, overflow) = timestamp.add_seconds_overflowing(seconds); - let datetime: NaiveDateTime = timestamp.into(); + let datetime: NaiveDateTime = Self::from_timestamp(timestamp); (datetime, overflow) } #[must_use] - pub fn add_nanoseconds_overflowing(self, nanoseconds: i64) -> (Self, bool) { - let timestamp: UnixTimestamp = self.into(); + pub const fn add_nanoseconds_overflowing(self, nanoseconds: i64) -> (Self, bool) { + let timestamp: UnixTimestamp = self.timestamp(); let (timestamp, overflow) = timestamp.add_nanoseconds_overflowing(nanoseconds); - let datetime: NaiveDateTime = timestamp.into(); + let datetime: NaiveDateTime = Self::from_timestamp(timestamp); (datetime, overflow) } @@ -191,6 +286,7 @@ impl<Tz: TimeZone> Display for DateTime<Tz> { } } +// TODO there's a lossy cast somewhere here or in the into(). Where is it? impl From<UnixTimestamp> for NaiveDateTime { fn from(timestamp: UnixTimestamp) -> Self { const UNIX_EPOCH_DAYS_AFTER_CE: i64 = Date::UNIX_EPOCH.days_after_common_era(); |
