Emit zone-aware UTC timestamp with real sub-second (not naive local + fake .000000)#14
Open
ACETyr wants to merge 2 commits into
Open
Conversation
… fake .000000) The packet/raw `timestamp` was built from localtime() (naive, no zone) at publish time with a hardcoded ".000000" sub-second. Aggregators that assume UTC (e.g. CoreScope) clamp a naive value landing >15 min off their clock to ingest time and flag the observer as clock-skewed — so emitting local time actively degrades ingest. Now format from gmtime() with an explicit Z, and use gettimeofday() for a genuine microsecond fraction (SNTP-maintained on ESP32) instead of the literal ".000000". Real sub-second helps consumers correlating off the raw MQTT feed; second-resolution consumers (CoreScope) simply truncate it. Note: this stamps publish time; threading the queued RX capture (QueuedPacket has a millis() timestamp) for true receive time is a worthwhile follow-up. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ACETyr
added a commit
to ACETyr/MeshCore
that referenced
this pull request
Jun 14, 2026
PR agessaman#14 fixed the packet timestamp, but the two status-message builders in MQTTBridge.cpp still formatted a hardcoded ".000000" via getLocalTime(). Use the same gettimeofday() + gmtime() + ".%06ldZ" pattern so the status timestamp is unambiguous UTC with a real sub-second, consistent with the packet builder (and not naive local, which a CoreScope-style aggregator would clamp/flag). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PR agessaman#14 fixed the packet timestamp, but the two status-message builders in MQTTBridge.cpp still formatted a hardcoded ".000000" via getLocalTime(). Use the same gettimeofday() + gmtime() + ".%06ldZ" pattern so the status timestamp is unambiguous UTC with a real sub-second, consistent with the packet builder (and not naive local, which a CoreScope-style aggregator would clamp/flag). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author
|
Added the status-message timestamp fix per the "possible follow-ups" note above. Both status builders in |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Make the MQTT observer's packet/raw
timestampa zone-aware UTC value with a real sub-second,instead of naive local time stamped at publish with a hardcoded
.000000.src/helpers/MQTTMessageBuilder.cpp(all three builders): format fromgmtime()with an explicitZsuffix, and take the fractional second from
gettimeofday()(genuine microseconds, SNTP-maintained onESP32) rather than the literal
.000000.Why
The
timestampwas built withlocaltime(timezone ? timezone->toLocal(now) : now)→ a zone-lessstring, and
time(nullptr)→ whole seconds with a literal.000000.Verified against a representative consumer's ingest code (CoreScope,
github.com/Kpa-clawbot/CoreScope,cmd/ingestor/main.goresolveRxTime):with ingest time, and the observer is flagged clock-skewed. So an observer that emits local time
(e.g. UTC+2) has every packet treated as ~2 h in the future and clamped — emitting local time
actively degrades ingest. A
Z-suffixed UTC value is trusted (even for buffered/late uploads)..000000is fabricated (there is no sub-second source today). That's misleading. CoreScopetruncates any fraction to whole seconds — but that's its current choice; consumers self-logging and
correlating directly off the MQTT feed (single-observer ordering, inter-arrival, airtime/collision
windows) genuinely benefit from a real sub-second, so this PR provides one rather than dropping it.
Measured impact context: across the public observer fleet, ~27% of observers already trip the
naive-clamp (local-time publishers); this change keeps an observer on the trusted path.
Testing
pio run -e Heltec_v3_repeater_observer_mqtt→ SUCCESS (ESP32-S3 image built).Scope / possible follow-ups (not in this PR)
MQTTBridge.cpp(publishStatus) — sametreatment should apply there for consistency; happy to include if preferred.
QueuedPacketalready captures amillis()at reception; threading a captured wall-clock from there would make the timestamp the true receive
instant even under queue backlog. Larger change — left as a follow-up.