Skip to content

datetime.time comparisons and hashing mishandle sub-minute UTC offsets #155023

Description

@yangbaechu

Bug report

Bug description:

The datetime.time documentation specifies:

If both comparands are aware and have different tzinfo attributes, the comparands are first adjusted by subtracting their UTC offsets.

UTC offsets have supported seconds and microseconds since Python 3.7 (gh-49538), but parts of the datetime.time implementation handle them incorrectly.

The C implementation can consider different normalized times equal and give them different hashes:

from datetime import time, timedelta, timezone

a = time(0, tzinfo=timezone(timedelta(microseconds=1)))
b = time(0, tzinfo=timezone(timedelta(microseconds=2)))

print(a == b)              # True, expected False
print(hash(a) == hash(b))  # False, despite a == b

The pure Python implementation also compares valid values incorrectly and raises an internal assertion while hashing:

import _pydatetime as datetime

a = datetime.time(12, tzinfo=datetime.timezone.utc)
b = datetime.time(
    12, 0, 1,
    tzinfo=datetime.timezone(datetime.timedelta(seconds=1)),
)

print(a == b)  # False, expected True
hash(b)        # AssertionError: whole minute

The comparison should use the complete normalized value wall time - UTC offset. The pure Python comparison uses minute floor division for the offset, while the C comparison omits the offset's microseconds. The pure Python hash also assumes a whole-minute offset.

I am working on a PR with regression tests for both implementations.

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    extension-modulesC modules in the Modules dirstdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions