From 0368ef08ebb6c19b150a296e0a34aa86c77614cd Mon Sep 17 00:00:00 2001 From: Bas Schoenmaeckers Date: Wed, 11 Dec 2024 14:14:17 +0100 Subject: [PATCH] use `datetime.fold` to distinguish ambiguous datetimes when converting --- newsfragments/4791.fixed.md | 1 + src/conversions/chrono.rs | 27 +++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 newsfragments/4791.fixed.md diff --git a/newsfragments/4791.fixed.md b/newsfragments/4791.fixed.md new file mode 100644 index 00000000000..7036038fba4 --- /dev/null +++ b/newsfragments/4791.fixed.md @@ -0,0 +1 @@ +use `datetime.fold` to distinguish ambiguous datetimes when converting to `chrono::DateTime` diff --git a/src/conversions/chrono.rs b/src/conversions/chrono.rs index 90f9c69761d..95f44a2c034 100644 --- a/src/conversions/chrono.rs +++ b/src/conversions/chrono.rs @@ -61,7 +61,8 @@ use crate::{intern, DowncastError}; use crate::{IntoPy, ToPyObject}; use chrono::offset::{FixedOffset, Utc}; use chrono::{ - DateTime, Datelike, Duration, NaiveDate, NaiveDateTime, NaiveTime, Offset, TimeZone, Timelike, + DateTime, Datelike, Duration, LocalResult, NaiveDate, NaiveDateTime, NaiveTime, Offset, + TimeZone, Timelike, }; #[allow(deprecated)] @@ -493,12 +494,26 @@ impl FromPyObject<'py>> FromPyObject<'_> for DateTime Ok(value), + LocalResult::Ambiguous(earliest, latest) => { + #[cfg(not(Py_LIMITED_API))] + let fold = dt.get_fold(); + + #[cfg(Py_LIMITED_API)] + let fold = dt.getattr(intern!(dt.py(), "fold"))?.extract::()? > 0; + + if fold { + Ok(latest) + } else { + Ok(earliest) + } + } + LocalResult::None => Err(PyValueError::new_err(format!( + "The datetime {:?} contains an incompatible timezone", dt - )) - }) + ))), + } } }