I think, that I have found bug in datetime module in Python 3.9.2.
When I compute difference/timedelta of datetimeaware objects of noons nearest after and before so-called dayling saving time, I get exactly 1 day, e.g. 24 hours.
But when I convert them to the same moments with UTC timezone, I get 23 hours.
In my opinion: The first result is bug, the second one is correct.
You can reproduce the alleged bug by this code:
(I use non-standard module dateutil for simple tzinfo creation.)
from datetime import datetime
from dateutil import tz
CET = tz.gettz('Europe/Amsterdam') # because Guido van Rossum ;-)
UTC = tz.gettz('UTC')
before_CET = datetime(2023, 3, 25, hour=12, tzinfo=CET)
after_CET = datetime(2023, 3, 26, hour=12, tzinfo=CET)
before_UTC = before_CET.astimezone(tz=UTC)
after_UTC = after_CET.astimezone(tz=UTC)
print("All datetime.datetime instances are aware:")
print(f"before_CET.tzinfo={before_CET.tzinfo}")
print("before_CET.tzinfo.utcoffset(before_CET)"
f"={before_CET.tzinfo.utcoffset(before_CET)}")
print(f"after_CET.tzinfo={after_CET.tzinfo}")
print("after_CET.tzinfo.utcoffset(after_CET)"
f"={after_CET.tzinfo.utcoffset(after_CET)}")
print(f"before_UTC.tzinfo={before_UTC.tzinfo}")
print("before_UTC.tzinfo.utcoffset(before_UTC)"
f"={before_UTC.tzinfo.utcoffset(before_UTC)}")
print(f"after_UTC.tzinfo={after_UTC.tzinfo}")
print("after_UTC.tzinfo.utcoffset(after_UTC)"
f"={after_UTC.tzinfo.utcoffset(after_UTC)}\n")
print("The same aware objects with changed timezone give distinct timedetlas:")
print(f"{after_CET.isoformat(timespec='hours')}"
f" - {before_CET.isoformat(timespec='hours')} = {after_CET-before_CET}")
print(f"{after_UTC.isoformat(timespec='hours')}"
f" - {before_UTC.isoformat(timespec='hours')} = {after_UTC-before_UTC}")
Please, is this real bug or strange intentional feature of the module?
ââ"
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.
ââ"
Personally, I think this isnât unreasonable behaviour. How long is it from today at noon until tomorrow at noon? One day. If you want to know the exact number of seconds that will elapse, you can do as youâve done in this demo and convert both to UTC, which then makes them points on a timeline rather than points on a calendar.
This is yet another demonstration of how, no matter what you do, Daylight Saving Time is a mess.
Sorry for bumping this old post, but I think itâs importent that this quirk would be addressed more explicitly by the language/documentation (Itâs not obvious for someone).
I would say itâs that considering DST for such cases would be the more intuitive behavior. If I ask long is it from today at noon until tomorrow at noon, and I receive a timedelta of (236060) seconds it would be a more correct and less ambiguate answer.
I could concede to the opposite point if it wasnât for the fact that the timedelta object defines a day as exactly 24 hours (which is how it calculates timedelta.total_seconds()). Because of this, I think there can be only one correct answer in this case.
That being said, can we do something about this? Obviously it would not be backwards compatible, so I assume we canât just change the semantics. But maybe we could implement one of the following solutions?
Introduce alternative methods (datetime.add, datetime.subtract) which always consider timezones
Mention this use-case as a warning in the documentation. Currently, this behavior IS documented, but only as a side note. I think we should add a warning for users who may not fully realize what this means for DSTs and such. We can also add an example code showing the difference, and a suggestion to convert the datetimes to UTC for users who donât want the current behavior.