You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fromdatetimeimportdatetimefromzoneinfoimportZoneInfo# 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.0print(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
Reacted by Maciej Olko, Kenrick Everett and Marek Madejski
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.
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".
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.
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.
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.
Activity
tim-one commentedon Dec 3, 2023
As the docs say for
datetime1 - datetime2,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
datetimeobjects were naive.m-aciek commentedon Dec 8, 2023
It looks like this implementation behaviour of
timedeltawas missed in PEP 495, and should/could have been covered? cc @abalkin @tim-oneThis should be extended to "have the same tzinfo and fold attributes, the tzinfo attributes are ignored".
tim-one commentedon Dec 8, 2023
I don't think so, alas. datetime arithmetic within a time zone was always intended to be naïve. If a
datetimeobject 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 (withtzinfomembersNoneor the same) should always return an hour, again regardless of anything related to time zones.foldwas 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.
tim-one commentedon Dec 10, 2023
Note that the referenced PEP does address this case explicitly:
And reiterates the intended approach:
Since everything is working here as designed and as documented, I'm going to close this.
tim-one commentedon Dec 10, 2023
Closing as "not planned".
m-aciek commentedon Dec 10, 2023
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.
uranusjr commentedon Dec 13, 2023
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.