Two timestamps answer different questions. Event time describes when a producer says something happened; observed time describes when a collector says it saw that event. Their difference is observed ingestion lag, subject to clock agreement. It is not automatically request latency. A request duration needs specified start/end boundaries and a clock suited to elapsed time, normally a monotonic clock within one process.
A UTC offset is part of a wall-time instant. Midnight UTC and 01:00 at +01:00 can denote the same instant, while identical local digits with different offsets can denote different instants. Parse timestamps into aware datetime values and normalize to UTC before comparison. A parseable but naive timestamp leaves its offset unspecified; this fixture rejects it.
from datetime import datetime, timezone
source = datetime.fromisoformat("2026-01-01T01:00:00+01:00")
print(source.astimezone(timezone.utc).isoformat(timespec="microseconds"))We preserve microseconds in the canonical output so formatting does not erase timestamp distinctions. The examples use wall-time fixtures, not live clocks or performance measurements. Even valid aware timestamps can disagree across machines. A negative observed-minus-event lag is a useful inconsistency to retain: changing it to its absolute value invents a positive delay and hides possible skew. Clock synchronization, timestamp precision and collection delay all matter in a real investigation.
Context answers “which work might these events belong to?” A request ID groups events for one request; a trace ID identifies a recorded trace; span IDs distinguish operations. Their scopes are different, and their propagation must be implemented across process boundaries. This lesson consumes supplied case-sensitive request IDs. It does not implement HTTP headers, generate globally unique IDs or prove that a producer propagated the right context.
Collection order can differ from event order because buffering and transport delay reorder records. The build groups by request ID and sorts normalized event instants within each group. An original-position tie-break preserves input order for equal instants. It does not manufacture a finer timeline. Service and event labels remain attached to each record so grouping does not erase where a claim originated.
A shared request label supports correlation. It does not show that the first sorted event caused the second. Retries can share an ID; a request can fan out; clocks can disagree; missing spans or logs may be sampled away. Keep observed facts separate from an inferred sequence. Later, an explicit dependency model will justify a limited critical-path calculation.
For practice, compare offset-equivalent timestamps, day-boundary conversions and equal-instant ties. Diagnose a transformation that sorts by collector arrival and another that hides negative lag. The build must handle a one-pass iterable, reject malformed context and return independent dictionaries without mutation. Before making a production chronology claim, ask which clock produced each timestamp and what collection coverage supports the sequence.