Skip to content

datetime and time equality and hashing problematic #116035

Open
@cjw296

Description

@cjw296

Bug report

Bug description:

I'm sure folks will pull out reasoning behind this from the inscrutable section in PEP 495 but this behaviour is honestly extremely surprising at best and just flat out wrong on first glance:

>>> from datetime import time, datetime, date
>>> time(fold=1) == time(fold=0)
True
>>> hash(time(fold=1)) == hash(time(fold=0))
True
>>> datetime(2024, 10, 27, fold=1) == datetime(2024, 10, 27, fold=0)
True
>>> hash(datetime(2024, 10, 27, fold=1)) == hash(datetime(2024, 10, 27, fold=0))
True

Even when deliberately specifying as explicitly as possible two points in time which are absolutely not the same (these are two points during the UK DST backwards transition later this year):

>>> from zoneinfo import ZoneInfo
>>> tz = ZoneInfo('Europe/London')
>>> dt1 = datetime(2024, 10, 27, 1, 30, fold=0, tzinfo=tz)
>>> dt2 = datetime(2024, 10, 27, 1, 30, fold=1, tzinfo=tz)
>>> dt1 == dt2 
True
>>> hash(dt1) == hash(dt2)
True

This has really unpleasant implications for things like storing points in time in a dictionary:

>>> d = {}
>>> d[dt1] = 1
>>> d[dt2] = 2
>>> d[dt1]
2
>>> d[dt2]
2

The inverse of this issue is reported in #115845.

Yes, I know the timestamp can be used:

>>> dt1.timestamp() == dt2.timestamp()
False

...but not on time objects, and timestamp also brings the local machine's timezone into play:

>>> def fold_equal(*args, **kw):
...   return datetime(*args, **kw, fold=0).timestamp() == datetime(*args, **kw, fold=1).timestamp()
... 
>>> fold_equal(2024, 10, 27, 0, 30)
True
>>> fold_equal(2024, 10, 27, 1, 30)
False
>>> fold_equal(2024, 10, 27, 2, 30)
True
>>> fold_equal(2024, 10, 27, 0, 30, tzinfo=ZoneInfo('America/Chicago'))
True
>>> fold_equal(2024, 10, 27, 1, 30, tzinfo=ZoneInfo('America/Chicago'))
True
>>> fold_equal(2024, 10, 27, 2, 30, tzinfo=ZoneInfo('America/Chicago'))
True

Concretely, it would be a lot less confusing if:

  • time objects, and datetime objects where tzinfo is None are equal and hashed the same only if all of their attributes including fold are the same.

  • datetime objects where tzinfo is not None are equal and hashed the same only if they represent the exact same point in time.

CPython versions tested on:

3.12

Operating systems tested on:

No response

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    docsDocumentation in the Doc dir

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions