Skip to content

Conversation

bschoenmaeckers
Copy link
Member

@bschoenmaeckers bschoenmaeckers commented Jun 4, 2025

This special cases chrono's DateTime<Local> from python conversion to allow naive datetimes. As suggested in #5169 (comment).

ref #5169, #5174

Copy link
Member

@davidhewitt davidhewitt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this seems like a good convenience for the flexibility. The need to remove the FromPyObject is a bit unfortunate but I don't see a good alternative way to solve it, and I think it's worth doing for users' sake?

Comment on lines -477 to -479
#[cfg(feature = "chrono-local")]
impl FromPyObject<'_> for Local {
fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult<Local> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing this is breaking, but I guess it's unlikely to be a problem? The DateTime conversion is still going to work and I would be quite surprised if users ever tried to extract Local directly.

Regardless we should add a 5178.removed.md entry in the changelog which says this implementation is no longer provided by the chrono-local feature.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You removing this is unfortunate. An other option is to conditionally branch on TypeId. Which in const is nicely optimized away.

Do you prefer the following over removing impl FromPyObject<'_> for Local?

impl<Tz: TimeZone + 'static + for<'py> FromPyObject<'py>> FromPyObject<'_> for DateTime<Tz> {
    fn extract_bound(dt: &Bound<'_, PyAny>) -> PyResult<DateTime<Tz>> {
        let dt = dt.downcast::<PyDateTime>()?;
        let tzinfo = dt.get_tzinfo();

        let tz = if let Some(tzinfo) = tzinfo {
            tzinfo.extract()?
        } else {

            // TODO make this check const when PartialEq is const stable
            #[cfg(feature = "chrono-local")]
            if TypeId::of::<Tz>() == TypeId::of::<Local>() {
                // Safety: Tz is Local, so we can safely transmute Local to Tz.
                let tz = unsafe { std::mem::transmute(Local) };
                return py_datetime_to_datetime_with_timezone(dt, tz);
            }

            return Err(PyTypeError::new_err(
                "expected a datetime with non-None tzinfo",
            ));
        };

        py_datetime_to_datetime_with_timezone(dt, tz)
    }
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never mind, this does not work in practice.

error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
   --> src\conversions\chrono.rs:341:35
    |
341 |                 let tz = unsafe { std::mem::transmute(Local) };
    |                                   ^^^^^^^^^^^^^^^^^^^
    |
    = note: source type: `Local` (0 bits)
    = note: target type: `Tz` (this type does not have a fixed size)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One option might be to add a hidden specialization to the FromPyObject trait similar to #5244

Though if we go that way, probably we should land this in 0.27 when I think we'll land the rest of the FromPyObject changes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never mind, this does not work in practice.

error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
   --> src\conversions\chrono.rs:341:35
    |
341 |                 let tz = unsafe { std::mem::transmute(Local) };
    |                                   ^^^^^^^^^^^^^^^^^^^
    |
    = note: source type: `Local` (0 bits)
    = note: target type: `Tz` (this type does not have a fixed size)

transmute_copy does work here. I wander if there is a safe api to do the TypeId::of check and transmute safely that optimises nicely 🤔.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants