Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

timedelta fails to consider fold #112638

Closed
uranusjr opened this issue Dec 3, 2023 · 7 comments
Closed

timedelta fails to consider fold #112638

uranusjr opened this issue Dec 3, 2023 · 7 comments
Labels
type-bug An unexpected behavior, bug, or error

Comments

@uranusjr
Copy link
Contributor

uranusjr commented Dec 3, 2023

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

@tim-one
Copy link
Member

tim-one commented Dec 3, 2023

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.

@m-aciek
Copy link
Contributor

m-aciek commented Dec 8, 2023

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".

@tim-one
Copy link
Member

tim-one commented Dec 8, 2023

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.

@tim-one
Copy link
Member

tim-one commented Dec 10, 2023

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.

@tim-one tim-one closed this as completed Dec 10, 2023
@tim-one tim-one reopened this Dec 10, 2023
@tim-one
Copy link
Member

tim-one commented Dec 10, 2023

Closing as "not planned".

@tim-one tim-one closed this as not planned Won't fix, can't repro, duplicate, stale Dec 10, 2023
@m-aciek
Copy link
Contributor

m-aciek commented 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
Copy link
Contributor Author

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
Labels
type-bug An unexpected behavior, bug, or error
Projects
Archived in project
Development

No branches or pull requests

3 participants