Expand description
timeglyph — forensic timestamp decipherment.
A timestamp is time inscribed as a symbol — the raw integer or bytes a system writes to mean an instant. This crate deciphers those inscriptions: it decodes a known format to an instant, encodes an instant to any format, and — the differentiator — identifies an unknown value by reporting every plausible interpretation, scored, with stated assumptions, never “the answer” (a single integer is usually underdetermined).
§Design (see docs/decisions/ for the ADRs)
- Canonical spine:
PosixNs— nanoseconds since the Unix epoch, proleptic Gregorian, leap-second-ignoring (POSIX). It is not called UTC: UTC has discontinuities POSIX pretends away. Leap-aware scales (TAI/GPS/NTP) get their own instant types (to be added behind ahifitimefeature). - Calendar/tz math is reused (
jiff), never reinvented. The value-add is the cited forensic format registry + scored auto-detection + byte decode. - Panic-free (Paranoid Gatekeeper): every length/offset/width is checked.
§Example
// Identify an unknown value: every plausible reading, ranked and scored —
// never a single verdict (a raw value is usually underdetermined).
let candidates = timeglyph::interpret::interpret_int(1_577_836_800);
let top = &candidates[0];
assert_eq!(top.format_id, "unix");
assert_eq!(top.rendered.as_deref(), Some("2020-01-01T00:00:00Z"));
// Or decode under one known format by id.
let filetime = timeglyph::format("filetime").unwrap();
let instant = filetime.decode_int(132_223_104_000_000_000).unwrap();
assert_eq!(instant.to_rfc3339().as_deref(), Some("2020-01-01T00:00:00Z"));§Further reading
The authoritative, primary-source-cited reference for every supported format — epochs, encodings, calendars, leap seconds, and the rollovers that eventually break them — lives at https://securityronin.github.io/timeglyph/.
Re-exports§
pub use datefmt::DateStyle;pub use localzone::resolve_local;pub use localzone::LocalResolution;
Modules§
- cal
- Bounded carve: find timestamps at every offset of a raw byte blob
(
identify_bytesswept over offsets, window + score-thresholded). Forensic calendar: civil facts of a date (ISO week, day-of-year, JDN/MJD, Unix midnight, weekday), the base of thecalsubcommand.timeglyph cal— a forensics-grade calendar. This module is the pure data builder: [build_day] computes the civil + timezone facts of a date (ISO week, day-of-year, Julian Day Number, Modified JD, Unix midnight, weekday, per-day UTC offset, DST fold/gap, and — behind theleapfeature — leap-second days and GPS week) with zero I/O, so it is fully testable and serialisable. Alternative calendars, the moon/season visual layer, rendering, and the CLI live in sibling modules built on top of this. - cal_art
- ASCII art (moon discs, seasonal tiles) for the
calvisual layer. ASCII art for thecalvisual layer: moon-phase discs and seasonal scene tiles. These are a rendering of values computed incrate::cal(the phase index, the season) — never a value themselves — so the art is a pure lookup keyed by an integer, snapshot-tested under the tier-1 astronomy tests.@= lit,.= dark; single-width ASCII only (no box-drawing). - cal_
render - Pure text renderers for the
calmonth grid. Pure renderers forcrate::cal— turn a [CalMonth] into a monospace text calendar for the terminal. No I/O, no colour side effects here: the grid uses spaces only (never box-drawing characters, which misalign across fonts), one marker glyph per day, and an ISO-week gutter. Machine (--json) output is the serde serialisation ofCalMonth/CalDay, not produced here. - carve
- Bounded carve: slide
identify_bytesover a blob and report scored hits per offset — the validatable core of “find timestamps in raw bytes” (a malware config blob, a hex selection, one record). - compose
- Composite (two-word) timestamp decode: values split across two integer
fields. Some artifacts store a timestamp as two halves rather than one
integer — a FILETIME as its
dwLowDateTime/dwHighDateTimeDWORDs in.regexports, IEindex.datcookies, and packed malware configs. This reassembles the halves and decodes via the canonical single-value path, so the same epoch math applies. No single-value converter reconstructs these. - csv_
enrich - CSV enrichment: add human-readable timestamp columns to a CSV.
- datefmt
- Datetime display styles shared by the CLI and the timeglyph-lens overlay.
- holiday
- Whole-world public-holiday lookup (ISO-3166 country + date → holiday name),
behind the
holidayfeature. An embedded python-holidays export; a hit is “consistent with a public holiday”, an annotation rather than a guarantee. Whole-world public-holiday lookup, behind theholidayfeature. - interpret
- Auto-detection: identify an unknown value by reporting EVERY plausible interpretation, scored, with stated assumptions — never “the detected format.” A single integer is usually underdetermined: a 64-bit value can be a plausible Unix-s, Java-ms, Chrome-µs, FILETIME, .NET-ticks and Cocoa-s date all at once. Presenting one as the answer would fabricate certainty, which a forensic tool must never do (epistemics: “consistent with”, not a verdict).
- leap
- Leap-aware time scales (GPS/TAI/NTP), behind the
leapfeature. Kept separate from the POSIXPosixNsspine (ADR 0003). Leap-aware time scales — GPS, TAI64, NTP — deliberately kept OUT of thePosixNsspine (ADR 0003). GPS and TAI are genuinely leap-aware: their UTC rendering applies the IERS leap-second table via thehifitimecrate (leap math is solved; we do NOT reinvent it). NTP follows UTC and does NOT count leap seconds, so its conversion is additive (reused viajiff); it is grouped here for the era-rollover handling, not for leap math. - localzone
- Resolve a
LocalNaivewall-clock value in a concrete zone — DST fold/gap (correctness wave). Pure over the IANA tzdb. Interpreting aLocalNaivewall-clock value in a concrete zone. - lunisolar
- Chinese lunisolar calendar + 干支 four-pillar rendering, behind the
lunisolarfeature. Convention-relative: needs a meridian (and optional longitude), unlike the instant↔instant rest of the crate. Chinese lunisolar calendar + 干支 (Heavenly-Stem / Earthly-Branch) four-pillar rendering, behind thelunisolarfeature. - mcp
- MCP (Model Context Protocol) stdio JSON-RPC handler — expose the engine as
tools for LLM-driven DFIR (cited readings, not hallucinated epoch math).
MCP (Model Context Protocol) JSON-RPC handler over stdio. Exposes the engine
as tools —
identify,decode,explain— so an LLM-driven DFIR workflow gets a cited, reproducible reading instead of a hallucinated epoch conversion (LLMs are reliably wrong at FILETIME↔Unix arithmetic). The handler is a pure function; themcpsubcommand is a thin stdin→[handle]→stdout loop over it. - registry
- The forensic format registry — the ENGINE half of the knowledge/engine split.
- scan
- Scan arbitrary text for timestamp candidates and decode each into ranked
readings (the CLI
scancommand and the timeglyph-lens overlay share this). Scan arbitrary text for timestamp candidates and decode each into ranked readings. Three extractors — long digit runs ([scan_numbers]), self-describing datetime strings ([datetime_candidates]), and raw-hex tokens ([hex_candidates]) — feedinterpret; [inspect_text] ties them together. Pure and GUI-free: it powers both the CLIscancommand and the timeglyph-lens overlay.
Structs§
- Format
- One forensic timestamp format: the authoritative catalog record (
meta, the evidence metadata +Encoding, owned by forensicnomicon) plus the engine’s packed codec when the encoding isEncoding::Packed. Derefs tometa, sof.id,f.citation,f.tz,f.encoding, … read straight through to the catalog entry. - PosixNs
- The canonical internal instant: nanoseconds since 1970-01-01, POSIX
(leap-ignoring), proleptic Gregorian.
i128because some source epochs sit - Time
Format - One forensic timestamp format: evidence metadata, not just a converter.
Enums§
- Chrono
Error - Errors from decoding, encoding, or rendering a timestamp.
- Encoded
- The natural encoded value of a format: an integer (linear / embedded / packed) or a float (OLE / Julian / Excel / Cocoa double). Displays as the bare value.
- Encoding
- How a stored value maps to an instant. The engine reads this to decode.
- Leap
Semantics - Leap-second semantics. Most forensic epochs are POSIX (leap-ignoring); only the GPS/TAI/NTP family needs true leap math (handled by the engine’s separate leap-aware instant type).
- Packed
Layout - Identifies which packed bit-field layout an
Encoding::Packedformat uses. A packed timestamp is not a linear offset but calendar fields squeezed into an integer, so decoding it needs a dedicated unpacker. The knowledge table names the layout here; the engine (timeglyph) dispatches this tag to the unpacker that does the (calendar-aware) math. - Render
Zone - A target timezone for rendering an instant (
PosixNs). Presentation only — it never changes the underlying instant, just how it is displayed. The default (RenderZone::Utc) renders with aZsuffix. - TzSemantics
- Timezone semantics of a format’s stored value — NOT garnish: FAT stores local time, EXIF often lacks an offset, Event Logs store UTC but display local.
- Unit
- The tick unit a linear/embedded format counts in.
Constants§
- VERSION
- The engine’s version (
CARGO_PKG_VERSION), for callers that surface it — e.g. the timeglyph-lens overlay’s landing screen.
Functions§
- format
- Look up a registered format by id.
- registry_
digest - A deterministic 16-hex-character fingerprint of the format registry — each
entry’s
idandcitation, in catalog order. The provenance anchor for--provenance: the same engine build always yields the same digest, and any change to a format definition changes it, so a reading is traceable to the exact method version that produced it. Pure FNV-1a (no dependency). Iterates the authoritative forensicnomicon catalog (the source the engine wraps).