Skip to content

Commit

Permalink
Fix creating a DateTime with NaiveDateTime::{MIN, MAX}
Browse files Browse the repository at this point in the history
  • Loading branch information
pitdicker committed May 19, 2023
1 parent 4ac7509 commit 7a3747c
Showing 1 changed file with 47 additions and 2 deletions.
49 changes: 47 additions & 2 deletions src/offset/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,8 +473,8 @@ pub trait TimeZone: Sized + Clone {
/// Converts the local `NaiveDateTime` to the timezone-aware `DateTime` if possible.
#[allow(clippy::wrong_self_convention)]
fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<DateTime<Self>> {
self.offset_from_local_datetime(local)
.map(|offset| DateTime::from_utc(*local - offset.fix(), offset))
let local_result_offset = self.offset_from_local_datetime(local);
local_time_min_offset(local_result_offset, local).unwrap_or(LocalResult::None)
}

/// Creates the offset for given UTC `NaiveDate`. This cannot fail.
Expand All @@ -500,10 +500,55 @@ pub trait TimeZone: Sized + Clone {
}
}

/// Helper function to map `LocalResult<FixedOffset>` to `LocalResult<DateTime<Local>>`.
/// Returns `None` on out-of-range.
fn local_time_min_offset<Tz: TimeZone>(
local_result: LocalResult<Tz::Offset>,
local_time: &NaiveDateTime,
) -> Option<LocalResult<DateTime<Tz>>> {
Some(match local_result {
LocalResult::None => LocalResult::None,
LocalResult::Single(offset) => LocalResult::Single(DateTime::from_utc(
local_time.checked_sub_offset(offset.fix())?,
offset,
)),
LocalResult::Ambiguous(o1, o2) => LocalResult::Ambiguous(
DateTime::from_utc(local_time.checked_sub_offset(o1.fix())?, o1),
DateTime::from_utc(local_time.checked_sub_offset(o2.fix())?, o2),
),
})
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_fixed_offset_min_max_dates() {
for offset_hour in -23..=23 {
dbg!(offset_hour);
let offset = FixedOffset::east_opt(offset_hour * 60 * 60).unwrap();

let local_max = offset.from_utc_datetime(&NaiveDateTime::MAX);
assert_eq!(local_max.naive_utc(), NaiveDateTime::MAX);
let local_min = offset.from_utc_datetime(&NaiveDateTime::MIN);
assert_eq!(local_min.naive_utc(), NaiveDateTime::MIN);

let local_max = offset.from_local_datetime(&NaiveDateTime::MAX);
if offset_hour >= 0 {
assert_eq!(local_max.unwrap().naive_local(), NaiveDateTime::MAX);
} else {
assert_eq!(local_max, LocalResult::None);
}
let local_min = offset.from_local_datetime(&NaiveDateTime::MIN);
if offset_hour <= 0 {
assert_eq!(local_min.unwrap().naive_local(), NaiveDateTime::MIN);
} else {
assert_eq!(local_min, LocalResult::None);
}
}
}

#[test]
fn test_negative_millis() {
let dt = Utc.timestamp_millis_opt(-1000).unwrap();
Expand Down

0 comments on commit 7a3747c

Please sign in to comment.