-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
datetime subject to rounding? #89510
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
Comments
I found two datetimes at difference timezone whose difference is 0 but which don't compare equal. Python 3.9.5 (default, May 12 2021, 15:26:36)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import datetime as dt
>>> from zoneinfo import ZoneInfo
>>> for i in range(3):
... ref = dt.datetime(5327 + i, 10, 31, tzinfo=dt.timezone.utc)
... print(ref.astimezone(ZoneInfo(key='Europe/Rome')) == ref.astimezone(dt.timezone(dt.timedelta(seconds=3600))))
...
True
False
True
>>> for i in range(3):
... ref = dt.datetime(5327 + i, 10, 31, tzinfo=dt.timezone.utc)
... print(ref.astimezone(ZoneInfo(key='Europe/Rome')) - ref.astimezone(dt.timezone(dt.timedelta(seconds=3600))))
...
0:00:00
0:00:00
0:00:00 Is this a float rounding problem? If so I think it should be documented that datetimes bewhave like floats instead of like Decimal, although they have finite precision. |
Related: https://bugs.python.org/issue44831 |
It may or it may not be obvious to some, but in year 5328, October 31st is the last Sunday of October, which in Rome, as in the rest of EU, according to the 202X rules, means it’s the day we shift from summer time (in Rome UTC+2) to standard time (in Rome UTC+1). The shift supposedly happens at 3AM where it’s 2AM, so not at midnight, but the proximity to a daylight shift moment raises some eyebrows. This could explain why it doesn’t happen on the year before or after. (I’m curious if it happens on year 5334 which has the same setup, but I cannot check at the moment) |
Considering that I have found another pair of dates failing equality, and they are too on the last Sunday of October, the hypothesis of rounding in timezone code starts to look likely.... Python 3.7.9 (default, Jan 12 2021, 17:26:22) >>> import datetime, backports.zoneinfo
>>> d1 = datetime.datetime(2255, 10, 28, 7, 31, 21, 393428, tzinfo=datetime.timezone(datetime.timedelta(seconds=27060)))
>>> d2 = datetime.datetime(2255, 10, 28, 2, 0, 21, 393428, tzinfo=backports.zoneinfo.ZoneInfo(key='Europe/Rome'))
>>> d1 - d2
datetime.timedelta(0)
>>> d1 == d2
False Added Python 3.7 to the affected list. |
This is still reproducible at head (3.15 alpha), with both the C and Python versions of >>> import datetime, zoneinfo
>>> d1 = datetime.datetime(2255, 10, 28, 7, 31, 21, 393428, tzinfo=datetime.timezone(datetime.timedelta(seconds=27060)))
>>> d2 = datetime.datetime(2255, 10, 28, 2, 0, 21, 393428, tzinfo=zoneinfo.ZoneInfo(key='Europe/Rome'))
>>> d1 - d2
datetime.timedelta(0)
>>> d1 == d2
False >>> import sys
>>> sys.modules['_datetime'] = None
>>> sys.modules['_zoneinfo'] = None
>>> import datetime, zoneinfo
>>> d1 = datetime.datetime(2255, 10, 28, 7, 31, 21, 393428, tzinfo=datetime.timezone(datetime.timedelta(seconds=27060)))
>>> d2 = datetime.datetime(2255, 10, 28, 2, 0, 21, 393428, tzinfo=zoneinfo.ZoneInfo(key='Europe/Rome'))
>>> d1 - d2
datetime.timedelta(0)
>>> d1 == d2
False Looking at the Python implementation of return self._cmp(other, allow_mixed=True) == 0 And the Python implementation of myoff = self.utcoffset()
otoff = other.utcoffset()
# Assume that allow_mixed means that we are called from __eq__
if allow_mixed:
if myoff != self.replace(fold=not self.fold).utcoffset():
return 2
if otoff != other.replace(fold=not other.fold).utcoffset():
return 2 So we can dig in further in our example: >>> d1._cmp(d2, allow_mixed=True)
2
>>> d1.utcoffset() == d1.replace(fold=not d1.fold).utcoffset()
True
>>> d2.utcoffset() == d2.replace(fold=not d2.fold).utcoffset()
False
>>> d2.utcoffset()
datetime.timedelta(seconds=7200)
>>> d2.replace(fold=not d2.fold).utcoffset()
datetime.timedelta(seconds=3600) Okay, clearly this is a deliberate choice with differing timezone info when one of the datetimes is in a repeated interval (i.e.
|
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: