Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions src/dfe_engine/appmgmt/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import re
from collections.abc import Sequence
from dataclasses import dataclass, field
from datetime import UTC, datetime
from pathlib import Path
from typing import Any

Expand Down Expand Up @@ -363,9 +364,14 @@ def _last_increase(series: Sequence[tuple[float, float, float]]) -> float | None


def _epoch(value: Any) -> float | None:
"""Coerce a ClickHouse DateTime or numeric to a POSIX timestamp."""
"""Coerce a ClickHouse DateTime or numeric to a POSIX timestamp.

clickhouse-connect returns naive datetimes in UTC, so a naive value is read as
UTC rather than the host's local time.
"""
if value is None:
return None
if hasattr(value, "timestamp"):
return float(value.timestamp())
if isinstance(value, datetime):
aware = value if value.tzinfo is not None else value.replace(tzinfo=UTC)
return aware.timestamp()
return float(value)
35 changes: 35 additions & 0 deletions tests/unit/test_appmgmt/test_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
latest time any series MOVED, not the last time the loader reported.
"""

import time
from datetime import datetime
from zoneinfo import ZoneInfo

import pytest

from dfe_engine.appmgmt.operations import (
Expand Down Expand Up @@ -221,6 +225,37 @@ def test_an_instance_with_telemetry_is_reporting():
assert status.last_seen_epoch == 1757000000.0


@pytest.fixture
def sydney_local_time(monkeypatch: pytest.MonkeyPatch):
"""Run with a host timezone ten or eleven hours off UTC."""
monkeypatch.setenv("TZ", "Australia/Sydney")
time.tzset()
yield
monkeypatch.undo()
time.tzset()


def test_a_naive_clickhouse_datetime_is_read_as_utc_on_a_non_utc_host(
sydney_local_time,
):
# clickhouse-connect hands back naive datetimes that are UTC.
naive = datetime(2025, 9, 4, 15, 33, 20)
ch = PerQueryClickHouse({"AS last_seen": [(naive, 12)]})

status = OperationalReader(ch, "dfe").status("dfe-loader")

assert status.last_seen_epoch == 1757000000.0


def test_an_aware_datetime_keeps_its_own_zone(sydney_local_time):
aware = datetime(2025, 9, 5, 1, 33, 20, tzinfo=ZoneInfo("Australia/Sydney"))
ch = PerQueryClickHouse({"AS last_seen": [(aware, 12)]})

status = OperationalReader(ch, "dfe").status("dfe-loader")

assert status.last_seen_epoch == 1757000000.0


def test_uptime_reads_the_start_time_every_dfe_app_emits():
# A scalo-py service reports start_time_seconds and no process_start_time_seconds.
ch = PerQueryClickHouse(
Expand Down
Loading