Skip to content

timedelta fails to consider fold #112638

Closed as not planned
Closed as not planned

Description

@uranusjr

Bug report

Bug description:

from datetime import datetime
from zoneinfo import ZoneInfo

# DST ends at 3am, folding back to 2.
z = ZoneInfo('Europe/Zurich')

# The fold zone.
d0 = datetime(2023, 10, 29, 2, 30, fold=0, tzinfo=z)
d1 = datetime(2023, 10, 29, 2, 30, fold=1, tzinfo=z)

# This should be out of DST.
d2 = datetime(2023, 10, 29, 3, tzinfo=z)

# These are correct.
print(d2.timestamp() - d0.timestamp())  # 5400.0
print(d2.timestamp() - d1.timestamp())  # 1800.0

# These are not.
print(d2 - d0)  # datetime.timedelta(seconds=1800)
print(d2 - d1)  # datetime.timedelta(seconds=1800)

CPython versions tested on:

3.12

Operating systems tested on:

macOS

Activity

  1. tim-one commented on Dec 3, 2023

    @tim-one
    Member

    As the docs say for datetime1 - datetime2,

    If both are naive, or both are aware and have the same tzinfo attribute, the tzinfo attributes are ignored, and the result is a timedelta object t such that datetime2 + t == datetime1. No time zone adjustments are done in this case.

    So it's working as designed and documented. The intended way to do timezone-aware arithmetic is to convert inputs to UTC first, and do the arithmetic on UTC objects. Within a single timezone ("same tzinfo attribute"), arithmetic acts as if the datetime objects were naive.

  2. m-aciek commented on Dec 8, 2023

    @m-aciek
    Contributor

    Within a single timezone ("same tzinfo attribute"), arithmetic acts as if the datetime objects were naive.

    It looks like this implementation behaviour of timedelta was missed in PEP 495, and should/could have been covered? cc @abalkin @tim-one

    If both are naive, or both are aware and have the same tzinfo attribute, the tzinfo attributes are ignored, and the result is a timedelta object t such that datetime2 + t == datetime1. No time zone adjustments are done in this case.

    This should be extended to "have the same tzinfo and fold attributes, the tzinfo attributes are ignored".

  3. tim-one commented on Dec 8, 2023

    @tim-one
    Member

    I don't think so, alas. datetime arithmetic within a time zone was always intended to be naïve. If a datetime object says it's 1:30 AM in some time zone that switches DST mode at 2 AM on some days, then adding an hour should always say it's now 2:30 AM, regardless of the date and of everything else related to time zones. For consistency, then, subtracting a datetime that says 1:30 AM from a datetime that says 2:30 AM (with tzinfo members None or the same) should always return an hour, again regardless of anything related to time zones.

    fold was intended to enable faithful roundtrip conversion with other time zones (especially UTC), and that's all.

    Again, like it or not 😉, time zone aware arithmetic is intended to be done by converting to UTC first.

  4. tim-one commented on Dec 10, 2023

    @tim-one
    Member

    Note that the referenced PEP does address this case explicitly:

    As explained in the previous paragraph, timedelta addition ignores both fold and tzinfo attributes and so does intra-zone or naive datetime subtraction.

    And reiterates the intended approach:

    Naive and intra-zone comparisons will ignore the value of fold and return the same results as they do now. (This is the only way to preserve backward compatibility. If you need an aware intra-zone comparison that uses the fold, convert both sides to UTC first.)

    Since everything is working here as designed and as documented, I'm going to close this.

  5. tim-one commented on Dec 10, 2023

    @tim-one
    Member

    Closing as "not planned".

  6. m-aciek commented on Dec 10, 2023

    @m-aciek
    Contributor

    By the way, the timedelta docs don't inform about lack of support of folded tzaware timestamps nor about the necessity of converting to UTC). I think they should as someone could expect different behavior knowing about the fold attribute. I will try to issue a PR to extend the docs in this regard.

  7. uranusjr commented on Dec 13, 2023

    @uranusjr
    ContributorAuthor

    I was also thinking about amending the documentation to explain this somewhat; please do ping me if a PR is raised to call the behaviour out.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    type-bugAn unexpected behavior, bug, or error

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions