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_
color - Terminal colour (truecolor→256→16→mono ladder) for the
calvisual layer. Terminal colour for thecalvisual layer — a capability ladder (truecolor → 256 → 16 → monochrome) applied as ANSI SGR escapes. Colour is garnish: every marker/glyph is already a distinct character, so the monochrome output loses colour but never information. Detection lives in the shell (env is passed in, not read here) so the renderers stay pure and testable, and ANSI is never emitted into the machine (--json/--tsv) views. - 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. - calfmt
- Shared calendar-display formatters (Chinese lunar date / 干支 / solar term,
Hebrew & Islamic month names, 五行) — the DRY source for
caland the lens. Shared calendar-display formatters — the single source of truth for the Chinese lunar-date / 干支 / solar-term strings, the Hebrew and Islamic month names, and the 五行 (Five Element) assignment. Both thecalsubcommand (viacrate::cal_render) and thetimeglyph-lensoverlay consume these, so the two never drift. Pure string/char logic, no dependencies. - 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. - secs
- Whole-second convenience over the
PosixNsspine (filesystem/bodyfile use). Whole-second convenience over thePosixNsspine, for callers that store a plaini64Unix-seconds timestamp (filesystemFsMeta, bodyfile rows) rather than a full nanosecond instant. Thin wrappers — the epoch math still lives in the canonical converters; this only drops sub-second precision and the two- word/PosixNsceremony for the common “field → seconds” case.
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).