Happened at 09:58, Arrived at 10:07: Showing Two Times in an Activity Feed
In an activity feed built from outside sources, one timestamp is rarely enough. The moment something happened at the source and the moment your system heard about it can differ, sometimes by a lot. If you show only one, readers either trust a delayed item as fresh or see events in an order that contradicts what they know. This article proposes a dual timestamp display specification. It is a conditional design for your own product.
Primary artifact: the dual timestamp display specification
Store two fields per item, both as absolute instants in UTC:
- occurred_at: the time the source says it happened. May be absent.
- received_at: the time your system accepted it. Always set by you.
Never overwrite one with the other. Display rules:
- Primary label is occurred_at, worded 'Happened', shown in the viewer's local zone with the zone name visible somewhere.
- Secondary label is received_at, worded 'Received', shown only when it differs from occurred_at by more than a tolerance you choose. The example below uses 5 minutes purely as a hypothetical.
- If occurred_at is absent, show only 'Received' and the words 'source time not provided'. Do not copy received_at into the Happened slot.
- If occurred_at is later than received_at, the source clock or its zone may be wrong. Show 'Happened (as reported by source)' with a small notice, and keep the record, not correct it.
- Hovering or opening the item shows both full values including the zone.
Decision branches: ordering
Choose the default sort by the reader's task.
Branch A: readers reconstruct what happened. Sort by occurred_at, items without it placed by received_at and marked as such.
Branch B: readers check what is new since last visit. Sort by received_at, since an old event delivered late is new information to them.
Offer one default and a visible switch. Do not mix the two orders silently in one list.
Worked hypothetical
The feed holds four items, viewed in a zone one hour ahead of UTC:
- Item 1: occurred 09:58 UTC, received 10:07 UTC. Gap is 9 minutes, above the 5 minute tolerance, so both lines appear: Happened 10:58, Received 11:07 local.
- Item 2: occurred 10:10, received 10:11. Gap is 1 minute, so only Happened shows.
- Item 3: no occurred_at, received 10:12. Shows Received only, with the not provided note.
- Item 4: occurred 10:30, received 10:20. Occurred is later, so the clock notice appears.
Sorted by occurred_at (Branch A) the order is Item 1, Item 2, Item 3 placed by receipt at 10:12, Item 4. Sorted by received_at (Branch B) it is Item 1, Item 2, Item 4 at 10:20 is after Item 2 at 10:11 but before Item 3 at 10:12? No: 10:20 is later than 10:12, so the order is Item 1, Item 2, Item 3, Item 4. Both orders end up the same here, which is itself worth noting in a test: choose data where they differ, such as a late item received after all others.
Stop conditions
- Do not display a computed 'age' from a field that might be missing.
- Do not repair skewed times automatically.
- Do not hide the secondary line to make the feed look tidier if the gap is large.
Proposed acceptance tests (not yet performed)
- Render the four items above and compare lines shown to the rules.
- Change the viewer zone and expect the same instants to show different local clock times.
- Add an item received an hour after it occurred and expect Received to show.
- Remove occurred_at and expect no invented value.
- Toggle the sort and expect the late item to move.
- Check the zone name is reachable without a mouse.
These are proposed checks for a design, not results.