Course outline

Digital Forensics / Intermediate: artifact-specific offline analysis / Lesson 8

Build timelines that retain uncertainty

Combine normalized times with intervals, ties, semantic differences, and explicit source dependencies.

About 4 min readContent reviewed
On this page

Lesson goals

  • Distinguish display ordering from supported event ordering.
  • Use interval reasoning to avoid unsupported before-and-after claims.

Define the event before placing it on a line

A timeline row should identify the source, event meaning, raw time, normalized value where justified, and uncertainty. An application commit, a collector receipt, and a file import can represent different stages of the same workflow. Placing them on one line is useful only when those meanings remain visible. Do not replace every time with a generic occurred_at label that implies identical semantics. The fictional workshop case uses declared clocks and event records, not actual system observations. A precise-looking chart cannot improve the quality of the underlying temporal evidence.

Use stable sorting for presentation only

For known offset-aware values, sorting can create a reproducible display. The first program sorts synthetic rows by normalized UTC time and then by event id to make ties deterministic. The id tie-breaker is presentation policy, not evidence that one tied event happened first. Preserve equal-time status and source uncertainty in the real analytical table. A parser may not support leap-second representations or ambiguous local times; record those limitations rather than forcing unsupported values into an arbitrary ordering. This example uses only ordinary declared timestamps supported by the available datetime parser.

python Create a deterministic display while retaining a tie
from datetime import datetime, timezone
rows = [{"id":"e2","time":"2026-10-28T08:00:00+00:00"}, {"id":"e1","time":"2026-10-28T10:00:00+02:00"}, {"id":"e3","time":"2026-10-28T08:00:01+00:00"}]
key = lambda r: (datetime.fromisoformat(r["time"]).astimezone(timezone.utc), r["id"])
ordered = sorted(rows, key=key)
assert [r["id"] for r in ordered] == ["e1", "e2", "e3"]
assert key(rows[0])[0] == key(rows[1])[0]
print("display order deterministic; first two times tied")
Expected output
display order deterministic; first two times tied

The complete program sorts three local records and explicitly checks the equal normalized times. It measures no clock and establishes no causal or real-world order between e1 and e2. No external source is queried.

Represent supported error bounds as intervals

If a source time has a justified error bound, use an interval rather than a point. A can be placed strictly before B only when A’s latest possible time is earlier than B’s earliest possible time under the assumptions. Overlap leaves ordering unresolved. The second program checks that relation on invented integer intervals. It does not estimate any actual clock error. Unknown uncertainty must not be replaced by zero, and a constant skew correction needs evidence that the offset remained applicable across the relevant period. Clock drift and buffering can require a more careful model.

python Check strict temporal ordering under declared bounds
def definitely_before(a, b):
    assert a[0] <= a[1] and b[0] <= b[1]
    return a[1] < b[0]

assert definitely_before((10, 12), (13, 15)) is True
assert definitely_before((10, 14), (13, 15)) is False
assert definitely_before((10, 13), (13, 15)) is False
print("separated intervals order; overlap and touching do not")
Expected output
separated intervals order; overlap and touching do not

The complete program checks three finite interval relationships. The units are classroom time, not measured seconds from a device. Touching intervals do not establish strict precedence under this policy, and no clock calibration is performed.

Use relationships beyond temporal proximity

Event ids, transaction references, version transitions, and documented workflow edges can provide stronger relationships than nearby timestamps alone. Their meaning and uniqueness still need verification. A shared request id across two reports derived from the same log is not independent corroboration. Separate event time from receipt time and preserve sequence counters only within their documented source scope. A later log write may describe an earlier action, while batch import can assign one time to many records. Review these mechanisms before calling a timeline gap suspicious or interpreting a burst as a burst of human actions.

Show unresolved ordering in the narrative

Report the observed time values, conversion method, error assumptions, and which ordering claims survive them. Use before, after, overlapping, or unresolved only with an explained basis. If a conclusion depends on an unverified timezone or source clock, identify that dependency. Keep the raw table and reproducible display separate from the analytical narrative. The course’s calculations demonstrate temporal reasoning with created fixtures; they do not establish a real incident chronology, human intent, or legally authoritative event time. Honest uncertainty prevents a decorative timeline from becoming a misleading causal story.

Common errors and fixes

Tie-breaker order is reported as event order

Why it happens
Display determinism is confused with temporal evidence.
How to fix it
Label ties and preserve uncertainty.
Prevent it next time
Keep presentation keys separate from event-order claims.

Unknown clock error is set to zero

Why it happens
Missing evidence becomes invented precision.
How to fix it
Retain unknown uncertainty and bound conclusions accordingly.
Prevent it next time
Require a source for every correction or error bound.

Nearby times establish causality

Why it happens
Temporal proximity substitutes for a verified relationship.
How to fix it
Seek event or workflow corroboration and alternatives.
Prevent it next time
Explain dependencies in the timeline narrative.

Check your understanding

1. A spans 10–14 and B spans 13–15. Can A be called definitely earlier?

Show worked solution

No. The intervals overlap, so the supported model permits more than one ordering. Report overlap and seek independent sequence or workflow evidence. Do not select the midpoint as an exact time simply to obtain a clean line.

2. Why does sorting equal UTC times by id not solve chronology?

Show worked solution

The id is chosen for stable presentation and may have no temporal meaning. Preserve the equality, field semantics, and clock limits. A deterministic table is reproducible output, while actual precedence requires evidence from the sources or another supported relationship.

Key takeaways

  • A deterministic timeline can still contain unresolved event order.
  • Intervals retain supported uncertainty.
  • Temporal proximity is not causality.

Official references