Skip to content

fix: interpret naive detected_at as UTC when rendering alert timestamps#2305

Open
hiromi-dev wants to merge 1 commit into
elementary-data:masterfrom
hiromi-dev:fix/alert-detected-at-naive-utc-timezone
Open

fix: interpret naive detected_at as UTC when rendering alert timestamps#2305
hiromi-dev wants to merge 1 commit into
elementary-data:masterfrom
hiromi-dev:fix/alert-detected-at-naive-utc-timezone

Conversation

@hiromi-dev

@hiromi-dev hiromi-dev commented Jul 23, 2026

Copy link
Copy Markdown

Fixes #2304.

detected_at values loaded from the alerts table are naive datetimes stored in UTC. AlertModel.__init__ passed them directly to datetime.astimezone(), which interprets naive datetimes as local time. On hosts whose timezone is not UTC this produced alert timestamps showing the UTC value labeled with the local timezone (e.g. Time: 2026-07-22 09:08:22 JST for an alert actually detected at 18:08:22 JST), inconsistent with max_loaded_at in the same message which is correctly converted via convert_datetime_utc_str_to_timezone_str().

Changes:

  • AlertModel.__init__: attach UTC tzinfo to naive detected_at before converting; detected_at_utc is now always timezone-aware UTC. Timezone-aware inputs behave as before.
  • Unit tests covering naive/aware inputs, the timezone config, detected_at_utc, and the source freshness result_description end-to-end (pinned to a non-UTC local timezone via TZ so they fail without the fix regardless of CI timezone).

Summary by CodeRabbit

  • Bug Fixes

    • Corrected alert timestamp handling so timezone-free timestamps are consistently interpreted as UTC.
    • Improved conversion of alert detection times to local or specified timezones.
    • Standardized timezone formatting in source freshness alert descriptions.
  • Tests

    • Added coverage for UTC, local timezone, and timezone-aware alert timestamps.

detected_at values loaded from the alerts table are naive datetimes
stored in UTC. Passing them directly to datetime.astimezone()
interprets them as local time, so on non-UTC hosts the alert "Time:"
field showed the UTC value labeled with the local timezone,
inconsistent with max_loaded_at in the same message which is correctly
converted via convert_datetime_utc_str_to_timezone_str().

Attach UTC tzinfo to naive detected_at before converting;
detected_at_utc is now always timezone-aware UTC. Timezone-aware
inputs behave as before.

Fixes elementary-data#2304

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

👋 @hiromi-dev
Thank you for raising your pull request.
Please make sure to add tests and document all user-facing changes.
You can do this by editing the docs files in this pull request.

@hiromi-dev
hiromi-dev requested a deployment to elementary_test_env July 23, 2026 01:14 — with GitHub Actions Waiting
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Alert timezone handling

Layer / File(s) Summary
Normalize naive detection timestamps
elementary/monitor/alerts/alert.py
Naive detected_at values are treated as UTC before conversion and storage in detected_at_utc.
Validate timezone conversion and rendering
tests/unit/monitor/alerts/test_alert_models.py
Adds deterministic Tokyo timezone setup and tests for alert timestamp conversion, UTC awareness, and source freshness descriptions.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main fix: interpreting naive detected_at values as UTC for alert timestamps.
Linked Issues check ✅ Passed The changes address issue #2304 by normalizing naive detected_at values as UTC and adding tests for non-UTC hosts and source freshness output.
Out of Scope Changes check ✅ Passed The diff stays focused on the alert timestamp timezone fix and related tests, with no clear unrelated changes.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@elementary/monitor/alerts/alert.py`:
- Around line 61-67: Update the group timestamp calculation in the logic
containing min(alert.detected_at or datetime.max ...) so missing timestamps use
a timezone-aware UTC fallback, or are excluded before computing min, preventing
comparisons between naive and aware datetimes. Preserve the existing behavior
for present timestamps and add a regression test covering a group with one
normalized alert and one missing timestamp.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 20eeecac-516e-414b-9322-6620b4b0cbae

📥 Commits

Reviewing files that changed from the base of the PR and between 594b89d and 33e544e.

📒 Files selected for processing (2)
  • elementary/monitor/alerts/alert.py
  • tests/unit/monitor/alerts/test_alert_models.py

Comment on lines +61 to 67
# detected_at is stored in UTC, so a naive datetime must be
# interpreted as UTC rather than as the machine's local time.
if detected_at.tzinfo is None:
detected_at = detected_at.replace(tzinfo=tz.tzutc())
self.detected_at_utc = detected_at.astimezone(tz.tzutc())
self.detected_at = detected_at.astimezone(
tz.gettz(timezone) if timezone else tz.tzlocal()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Avoid mixing normalized timestamps with the group’s naive fallback.

After this change, a naive input produces an aware self.detected_at, but base_alerts_group.py:22-23 still evaluates min(alert.detected_at or datetime.max ...). A group containing one normalized alert and one missing timestamp now raises TypeError: can't compare offset-naive and offset-aware datetimes. Make that fallback timezone-aware (or exclude missing timestamps before min()) and add a mixed-group regression test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@elementary/monitor/alerts/alert.py` around lines 61 - 67, Update the group
timestamp calculation in the logic containing min(alert.detected_at or
datetime.max ...) so missing timestamps use a timezone-aware UTC fallback, or
are excluded before computing min, preventing comparisons between naive and
aware datetimes. Preserve the existing behavior for present timestamps and add a
regression test covering a group with one normalized alert and one missing
timestamp.

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.

Alert "Time" shows the UTC value labeled with the local timezone when the host timezone is not UTC

1 participant