Skip to content

Ensure consistent UTC timezone handling for timestamps#848

Open
helylle wants to merge 9 commits intomainfrom
ylle-datetime-linting
Open

Ensure consistent UTC timezone handling for timestamps#848
helylle wants to merge 9 commits intomainfrom
ylle-datetime-linting

Conversation

@helylle
Copy link
Contributor

@helylle helylle commented Feb 16, 2026

Enable DTZ ruff rules — datetime timezone safety

Summary

Enable the DTZ rule set in ruff to enforce timezone-aware datetime usage across the codebase. Fixes 39 issues, including a real bug in graphdb/helpers.py.

Bug fix

graphdb/helpers.py — discarded .replace() result

datetime.replace() returns a new object; the result was being discarded, leaving timestamps naive despite the developer's intent:

# Before (bug)
created_ts = datetime.fromtimestamp(created_ts / 1000)
created_ts.replace(tzinfo=UTC)  # no-op — return value discarded

# After (fixed)
created_ts = datetime.fromtimestamp(created_ts / 1000, tz=UTC)

Changes

Production code (18 issues)

File Issue Fix Status
graphdb/helpers.py fromtimestamp() without tz + discarded .replace() Pass tz=UTC, remove .replace()
webapp/common/api/oidc.py datetime.now() in circuit breaker Use utc_now()
webapp/freja_eid/proofing.py fromtimestamp() + naive date_of_birth constructors Add tz=UTC / tzinfo=UTC
webapp/eidas/proofing.py Naive date_of_birth constructors Add tzinfo=UTC
webapp/svipe_id/proofing.py Naive date_of_birth constructors Add tzinfo=UTC
webapp/letter_proofing/helpers.py fromtimestamp(0) sentinel value Add tz=UTC
userdb/admin/__init__.py fromtimestamp() in CLI tool Add tz=UTC
userdb/identity.py strptime() for NIN date parsing Add .replace(tzinfo=UTC)
webapp/lookup_mobile_proofing/helpers.py strptime() for age calc Add .replace(tzinfo=UTC)

Test code (21 issues)

Mechanical fixes — replaced datetime.now(tz=None) / datetime.today() / naive datetime() constructors with utc_now() or added tzinfo=UTC.

Ruff config

Added "DTZ" to the select list in ruff.toml.

date_of_birth safety analysis

Adding tzinfo=UTC to the 6 naive datetime() constructors in proofing code is safe:

  • MongoDB tz_aware=True — the pymongo connection already interprets naive datetimes as UTC on write and returns them as UTC-aware on read. The stored value is identical with or without tzinfo=UTC.
  • No comparison breakage — all date_of_birth comparisons use .date() (which strips timezone) or .strftime() (timezone-agnostic). No direct </> between naive and aware datetimes exists.
  • No validator conflicts — no Pydantic validator enforces or strips timezone on date_of_birth.
  • Consistency — makes the write side explicitly match what already happens on read-back.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Enables Ruff’s DTZ (datetime timezone safety) rules and updates code/tests to consistently use UTC-aware datetimes, including fixing an actual bug where a .replace(tzinfo=...) result was previously discarded.

Changes:

  • Enable Ruff DTZ ruleset to enforce timezone-aware datetime usage.
  • Update production code to create/handle UTC-aware timestamps (e.g., fromtimestamp(..., tz=UTC), utc_now(), tzinfo=UTC).
  • Update tests to avoid naive datetime constructors and use UTC-aware timestamps.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/eduid/webapp/svipe_id/tests/test_app.py Replace naive datetime.today() usage with utc_now() in test data.
src/eduid/webapp/svipe_id/proofing.py Ensure date_of_birth datetimes are created as UTC-aware.
src/eduid/webapp/security/tests/test_app.py Make test timestamps UTC-aware by adding tzinfo=UTC.
src/eduid/webapp/lookup_mobile_proofing/tests/test_app.py Use utc_now() instead of naive datetime.now() for underage test setup.
src/eduid/webapp/lookup_mobile_proofing/helpers.py Make parsed NIN birthdate UTC-aware for timezone-safe age calculations.
src/eduid/webapp/letter_proofing/helpers.py Make sentinel fromtimestamp(0) UTC-aware.
src/eduid/webapp/idp/tests/test_idPUserDb.py Use utc_now() for “three years ago” timestamp in tests.
src/eduid/webapp/idp/tests/test_SSO.py Make date_of_birth test identities UTC-aware.
src/eduid/webapp/freja_eid/tests/test_app.py Replace naive today/now usages in tests with utc_now().
src/eduid/webapp/freja_eid/proofing.py Ensure fromtimestamp and date_of_birth handling is UTC-aware.
src/eduid/webapp/email/tests/test_app.py Replace naive datetime.now(tz=None) in tests with utc_now().
src/eduid/webapp/eidas/tests/test_app.py Ensure parsed date_of_birth is UTC-aware in test auth response generation.
src/eduid/webapp/eidas/proofing.py Ensure date_of_birth datetimes are created as UTC-aware.
src/eduid/webapp/common/api/oidc.py Use utc_now() for circuit breaker timing instead of naive datetime.now().
src/eduid/webapp/bankid/tests/test_app.py Ensure parsed date_of_birth is UTC-aware in test auth response generation.
src/eduid/userdb/tests/test_user.py Make proofing timestamps in test fixtures UTC-aware.
src/eduid/userdb/tests/test_proofing.py Use utc_now() for proofing state timestamps in tests.
src/eduid/userdb/tests/test_event.py Make event timestamps UTC-aware and update assertions accordingly.
src/eduid/userdb/identity.py Ensure parsed NIN-derived date_of_birth is returned as UTC-aware.
src/eduid/userdb/admin/init.py Add UTC timezone to CLI tool timestamps used for backup paths.
src/eduid/graphdb/helpers.py Fix bug by using fromtimestamp(..., tz=UTC) so Neo4j timestamps become UTC-aware.
ruff.toml Add DTZ to Ruff lint selection.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@helylle helylle marked this pull request as ready for review February 17, 2026 09:42
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
11.3% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

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.

2 participants