Skip to content

Commit 0368ef0

Browse files
use datetime.fold to distinguish ambiguous datetimes when converting
1 parent 992865b commit 0368ef0

File tree

2 files changed

+22
-6
lines changed

2 files changed

+22
-6
lines changed

newsfragments/4791.fixed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
use `datetime.fold` to distinguish ambiguous datetimes when converting to `chrono::DateTime<Tz>`

src/conversions/chrono.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ use crate::{intern, DowncastError};
6161
use crate::{IntoPy, ToPyObject};
6262
use chrono::offset::{FixedOffset, Utc};
6363
use chrono::{
64-
DateTime, Datelike, Duration, NaiveDate, NaiveDateTime, NaiveTime, Offset, TimeZone, Timelike,
64+
DateTime, Datelike, Duration, LocalResult, NaiveDate, NaiveDateTime, NaiveTime, Offset,
65+
TimeZone, Timelike,
6566
};
6667

6768
#[allow(deprecated)]
@@ -493,12 +494,26 @@ impl<Tz: TimeZone + for<'py> FromPyObject<'py>> FromPyObject<'_> for DateTime<Tz
493494
));
494495
};
495496
let naive_dt = NaiveDateTime::new(py_date_to_naive_date(dt)?, py_time_to_naive_time(dt)?);
496-
naive_dt.and_local_timezone(tz).single().ok_or_else(|| {
497-
PyValueError::new_err(format!(
498-
"The datetime {:?} contains an incompatible or ambiguous timezone",
497+
match naive_dt.and_local_timezone(tz) {
498+
LocalResult::Single(value) => Ok(value),
499+
LocalResult::Ambiguous(earliest, latest) => {
500+
#[cfg(not(Py_LIMITED_API))]
501+
let fold = dt.get_fold();
502+
503+
#[cfg(Py_LIMITED_API)]
504+
let fold = dt.getattr(intern!(dt.py(), "fold"))?.extract::<usize>()? > 0;
505+
506+
if fold {
507+
Ok(latest)
508+
} else {
509+
Ok(earliest)
510+
}
511+
}
512+
LocalResult::None => Err(PyValueError::new_err(format!(
513+
"The datetime {:?} contains an incompatible timezone",
499514
dt
500-
))
501-
})
515+
))),
516+
}
502517
}
503518
}
504519

0 commit comments

Comments
 (0)