Naive local-time timestamps get mislabeled as UTC in log/telemetry export (causes false clock-skew warnings on downstream observers) #117

Closed
opened 2026-10-27 09:34:01 +01:00 by adam · 2 comments
Owner

Environment

  • openhop_repeater v1.1.2.dev1, core v1.1.1
  • Raspberry Pi 5, Debian 12 (Bookworm)
  • System timezone: America/Chicago (CDT, UTC-5), NTP-synced and confirmed correct
    (timedatectl shows "System clock synchronized: yes", "NTP service: active")

Symptom
A downstream MeshCore observer aggregator (NebraskaMesh Analyzer) flags this
repeater with: "emitting zone-less local-time timestamps ... clock is
currently 5.0h behind UTC" and repeated clamp events. The offset (5.0h)
exactly matches this system's CDT UTC offset, despite the Pi's system clock
being correctly NTP-synchronized. This points to a timestamp-formatting bug
rather than an actual clock problem.

Root cause

  1. repeater/web/http_server.py line 86:
   "timestamp": datetime.fromtimestamp(record.created).isoformat(),

Called without a tz argument, datetime.fromtimestamp() converts the
epoch value to a naive local-time datetime (no tzinfo attached)
instead of UTC.

  1. repeater/data_acquisition/glass_handler.py, _to_rfc3339_timestamp()
    (~lines 1146-1166):
   if dt.tzinfo is None:
       dt = dt.replace(tzinfo=timezone.utc)

When it receives one of these naive strings, it relabels the value
as UTC without converting it, rather than treating it as local time and
calling .astimezone(timezone.utc).

Combined effect: a timestamp that is actually local wall-clock time
(e.g., CDT) is exported over MQTT/Glass with a "Z" (UTC) suffix, producing
a systematic offset equal to the host's local UTC offset. Any repeater
running outside UTC will trigger this on downstream observers.

Suggested fix

  • Ensure all datetime.now() / datetime.fromtimestamp() calls feeding
    logs/telemetry pass tz=timezone.utc explicitly at creation, so values
    are timezone-aware from the start.
  • In _to_rfc3339_timestamp(), if a naive datetime is received, either
    reject/warn rather than silently stamping it UTC, or explicitly localize
    it using the system's local tzinfo before converting to UTC.

Impact: Likely affects every deployment running outside UTC — probably
the majority of installs — causing false clock-skew/clamp warnings and
corrupting propagation-delay analytics on any observer platform that
trusts the "Z" suffix.

I found this via the NebraskaMesh Analyzer's clamp-detection banner.

**Environment** - openhop_repeater v1.1.2.dev1, core v1.1.1 - Raspberry Pi 5, Debian 12 (Bookworm) - System timezone: America/Chicago (CDT, UTC-5), NTP-synced and confirmed correct (`timedatectl` shows "System clock synchronized: yes", "NTP service: active") **Symptom** A downstream MeshCore observer aggregator (NebraskaMesh Analyzer) flags this repeater with: "emitting zone-less local-time timestamps ... clock is currently 5.0h behind UTC" and repeated clamp events. The offset (5.0h) exactly matches this system's CDT UTC offset, despite the Pi's system clock being correctly NTP-synchronized. This points to a timestamp-formatting bug rather than an actual clock problem. **Root cause** 1. `repeater/web/http_server.py` line 86: ```python "timestamp": datetime.fromtimestamp(record.created).isoformat(), ``` Called without a `tz` argument, `datetime.fromtimestamp()` converts the epoch value to a **naive local-time** datetime (no tzinfo attached) instead of UTC. 2. `repeater/data_acquisition/glass_handler.py`, `_to_rfc3339_timestamp()` (~lines 1146-1166): ```python if dt.tzinfo is None: dt = dt.replace(tzinfo=timezone.utc) ``` When it receives one of these naive strings, it **relabels** the value as UTC without converting it, rather than treating it as local time and calling `.astimezone(timezone.utc)`. **Combined effect:** a timestamp that is actually local wall-clock time (e.g., CDT) is exported over MQTT/Glass with a "Z" (UTC) suffix, producing a systematic offset equal to the host's local UTC offset. Any repeater running outside UTC will trigger this on downstream observers. **Suggested fix** - Ensure all `datetime.now()` / `datetime.fromtimestamp()` calls feeding logs/telemetry pass `tz=timezone.utc` explicitly at creation, so values are timezone-aware from the start. - In `_to_rfc3339_timestamp()`, if a naive datetime is received, either reject/warn rather than silently stamping it UTC, or explicitly localize it using the system's local tzinfo before converting to UTC. **Impact:** Likely affects every deployment running outside UTC — probably the majority of installs — causing false clock-skew/clamp warnings and corrupting propagation-delay analytics on any observer platform that trusts the "Z" suffix. I found this via the NebraskaMesh Analyzer's clamp-detection banner. <!-- github-sync-id:4821606544 -->
adam closed this issue 2026-10-27 09:34:01 +01:00
Author
Owner

this has been worked on / fixed and reported here - https://github.com/openhop-dev/openhop_repeater/issues/305
and the PR https://github.com/openhop-dev/openhop_repeater/pull/333

just waiting to be tested and merged into dev/main

this has been worked on / fixed and reported here - https://github.com/openhop-dev/openhop_repeater/issues/305 and the PR https://github.com/openhop-dev/openhop_repeater/pull/333 just waiting to be tested and merged into dev/main <!-- github-comment-id:4895981999 -->
Author
Owner

Great news! Thank you.

Great news! Thank you. <!-- github-comment-id:4896146697 -->
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: adam/pyMC_Repeater#117