Skip to content

Restore hashing for named timezones - #1009

Open
emme1t wants to merge 2 commits into
python-pendulum:masterfrom
emme1t:fix/timezone-hashability
Open

emme1t wants to merge 2 commits into
python-pendulum:masterfrom
emme1t:fix/timezone-hashability

Conversation

@emme1t

@emme1t emme1t commented Sep 12, 2026

Copy link
Copy Markdown

Fixes #1008.

Adding Timezone.__eq__ in 3.1.0 made named timezone objects unhashable. This breaks calls such as hash(pendulum.Timezone("UTC")) and using a timezone as a dictionary key or set element.

Implement __hash__ using the timezone key, matching the existing equality rule. The regression tests construct equal objects with Timezone.no_cache() and verify equal hashes, dictionary lookup, and set deduplication. A separate test checks dictionary lookup for two distinct timezone names.

Validation

Tested locally on Windows with Python 3.13.13:

  • All four new regression cases fail on the original implementation.
  • Timezone suite: 638 passed, 5 skipped.
  • Complete pure-Python suite (PENDULUM_EXTENSIONS=0): 1,840 passed, 5 skipped, 2 failed. A clean checkout of the original commit produces the same two failures, with 1,836 passing tests. The failing tests are tests/date/test_diff.py::test_diff_for_humans_now_and_future_month and tests/test_parsing.py::test_parse.
  • The project's pinned Ruff 0.14.11 lint and format checks pass for both changed files.
  • The lockfile's Mypy 1.13.0 passes for all 223 source/test files.
  • git diff --check passes.

The native extension build could not run on this machine because the MSVC link.exe linker is unavailable. The Python source tests use the same pure-Python mode exercised by the repository's CI.

Pull Request Check List

  • Added tests for changed code.
  • Updated documentation for changed code (existing behavior is restored; no user-facing option changes).

This patch, regression tests, and PR description were prepared with OpenAI Codex assistance. The reported reproductions and tests were executed locally.

Comment thread src/pendulum/tz/timezone.py Outdated
return isinstance(other, Timezone) and self.key == other.key

def __hash__(self) -> int:
return hash(self.key)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is slightly incorrect, as it means that "UTC" and Timezone("UTC") would hash to the same value

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing this out. Updated in b623446 to hash (Timezone, self.key), giving named timezones a type-qualified hash input. Using the base Timezone class also preserves equal hashes for subclasses that inherit the existing equality behavior.

Added regression coverage for equal base/subclass instances as dictionary keys and set members across UTC, Europe/Paris, and America/New_York.

Local validation on Windows / CPython 3.13 in pure-Python mode: 641 timezone tests passed, 5 skipped. The full suite has 1,843 passed, 5 skipped, and the same two failures reproduced on the original upstream checkout (test_diff_for_humans_now_and_future_month and test_parse). Mypy 1.13.0 passes across 223 files. The Rust extension was not validated.

Ruff 0.14.11 lint and format checks pass as well. This patch and validation were prepared with Codex assistance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Timezones are not hashable

2 participants