Feature request: expose timestamps to Claude as structured data for time-aware reasoning

Status Closed — not planned
Maintainer reply None cached
Activity 14 comments · opened Apr 16, 2026 · closed Aug 16, 2026

Problem

Claude Code has no concept of time within a session. It cannot:

  • Know how long it's been since the last message or tool call
  • Correlate its own actions with external systems by time
  • Calculate durations between its own events
  • Detect stale state ("this agent has been running for 20 minutes, might be hung")
  • Make time-aware decisions ("5 minutes since last CI check, time to poll")
  • Build accurate timelines in session summaries

Currently the only workaround is shelling out to date, which is hacky and only gives "now" — not when past messages/results arrived.

Proposed solution

Expose timestamps as first-class data Claude can read and reason with:

  • Each message and tool result should carry a timestamp accessible to Claude
  • A lightweight way to get "now" without date shell calls
  • Durations between events should be computable
  • Background task notifications should include start time, not just completion time

Why this matters

Claude increasingly operates as a long-running orchestrator — managing parallel agents, polling CI, waiting on background tasks. Without time awareness it's flying blind on the temporal dimension. Time is a basic data point that every other development tool exposes.

Example use cases

  • "The benchmark started at 10:42 and finished at 11:18 — 36 minutes for 120 calls"
  • "Agent X has been running for 25 minutes vs Agent Y which finished in 3 — X might be stuck"
  • "Last CI poll was 8 minutes ago, checking again"
  • Session summaries with accurate timing, not guesses

View original on GitHub ↗

13 Comments

0xbrainkid · 4 months ago

Exposing timestamps as structured data for time-aware reasoning is the right approach — the current state where the model cannot reliably know the current time (and often hallucinates it or confuses it) is a fundamental capability gap for any time-sensitive task.

From an agent identity and behavioral trust perspective, an agent that fabricates timestamps is exhibiting the same "state a number without seeing it in actual tool output" failure documented in #49092. Temporal reasoning failures are in the same category as numerical hallucination: the model substitutes a plausible-seeming value for the actual value rather than querying the ground truth.

The structured data approach is correct because it makes the time visible in the model's context without requiring a tool call. A system-datetime injection:

{
  "type": "system",
  "subtype": "datetime-context",
  "timestamp_utc": "2026-04-16T09:41:13Z",
  "timezone": "Asia/Nicosia",
  "timestamp_local": "2026-04-16T12:41:13+03:00",
  "day_of_week": "Thursday",
  "unix_ms": 1744809673000
}

This gives the model: current UTC time, local timezone, and unix timestamp for math operations. Injecting this at session start and at every compaction boundary (since temporal awareness is lost at compaction — as documented in #48822) would significantly reduce temporal hallucination.

The unix_ms field is particularly useful for duration calculations — the model can compute time differences without needing to parse date strings. The day_of_week field avoids common hallucination of "Monday" when it is actually Thursday.

PranavGopinath · 4 months ago

Adding another example - not necessarily session specific.

When operating in different worktrees, agents seem to have no awareness of the chronological order of commits/features. Consider two worktrees started from main (A, B). From worktree A I had pushed a major feature upgrade (then merged into main). From worktree B, I planned to create a new branch C, and merge main into it to start working with the new feature. The agent decided that worktree B had DELETED the entire feature (5000 line pr) and continued to operate on its own. Having time as a baseline requirement would drastically improve reasoning capabilities in these kinds of contexts.

pleasedodisturb · 4 months ago

Built a workaround for this using the existing extensibility surfaces (hooks + MCP server), no upstream changes needed:

Passive time awareness — the claude-inject-idle-time plugin already injects a [timing] block on every user message via UserPromptSubmit hook (current time, idle duration, last turn duration — 42 tokens).

Active time queries — I've opened a PR to that plugin adding an MCP server with:

  • get_time — structured current time (ISO, UTC, unix, timezone)
  • time_diff — compute duration between two ISO timestamps
  • mark_event — record named session events (e.g. "build_started")
  • get_timeline — retrieve all events with inter-event durations

Plus a PostToolUse hook that logs every tool call to a per-session JSONL timeline automatically.

Zero runtime dependencies — the MCP server is hand-rolled JSON-RPC over stdio (~200 LOC), reuses the plugin's existing time/duration modules.

This covers the main use cases in the original issue:

  • ✅ "The benchmark started at 10:42 and finished at 11:18" → mark_event + get_timeline
  • ✅ "Last CI poll was 8 minutes ago" → time_diff with stored timestamp
  • ✅ Session summaries with accurate timing → get_timeline
  • ⚠️ "Agent X has been running for 25 minutes" → partially (can track spawn/return, but no mid-flight status query)

Install: /plugin marketplace add clankercode/claude-inject-idle-time

Other community solutions:

  • claude-code-timestamps — retrospective /timestamps command that reads .jsonl transcripts to show a timeline to the user (complements idle-timing which gives Claude real-time awareness)

Mockup of proposed native support:

!timestamp-mock

Still want native timestamp support on messages (#47160) — it would eliminate the need for the hook injection entirely and enable things we can't do from userspace (like timestamps surviving context compaction without a PreCompact hook).

pleasedodisturb · 4 months ago

Update: I've combined the two community plugins that tackle this into a single fork: pleasedodisturb/claude-inject-idle-time.

Sourced from:

The combined fork now covers all three dimensions:

  • Passive[timing] block injected on every prompt (hook)
  • Activeget_time, time_diff, mark_event, get_timeline (MCP server)
  • Retrospective/timestamps [count] slash command that parses the session transcript:
--- Message Timeline ---
14:32  You     can you refactor the auth middleware?
14:32  Claude  [tool: Read]
14:33  Claude  I'll restructure the middleware to separate...
14:38  You     looks good, now add tests

Install: claude plugin add --from https://github.com/pleasedodisturb/claude-inject-idle-time

Still a workaround — native timestamps on messages would make all of this unnecessary.

asakin · 4 months ago

+1 from a real session today (2026-04-27).

Concrete pain pattern from this morning's session with Claude Code: the harness injects currentDate once at session start, then never updates. After ~5 hours of active session with multiple breaks for meetings and a background agent run, I caught Claude assuming it was still session-start time when making a time-relative claim ("Blog post should be live or close to it"). It was 11:23 AM, not 9:30 AM. The post had been live for two hours.

The workaround Claude adopted (running date whenever making a time-relative claim) is doable as a discipline rule but exactly the kind of thing that should be infrastructural, not behavioral. Discipline rules degrade. Mechanical primitives don't.

Concrete ask, slightly more specific than the original body:

  1. Per-message timestamp injection — add a currentTime field that updates on every user-message turn (parallel to the existing currentDate). One-line change in the prompt assembly; closes 80% of the gap.
  1. Tool-result timestamps — when a Bash/Read/Agent result returns to Claude, include the wall-clock time it completed. The agent then knows "the background subagent ran for 4 minutes" without doing math against date calls.
  1. Optional but high-leverage — expose the timestamp of each message in the conversation, so Claude can answer "how long ago did we discuss X" without requiring continuous-context tracking on its side.

The first item is by far the most important and would unblock everything else.

Counter-pattern worth naming: today's workaround is for Claude to invoke date whenever making a time-relative claim. That works but is a tax on every response. With per-turn timestamps, the same agent could just know without burning a tool call.

— Filed by a guy who asked his agent for the time, watched it admit it had been frozen at session-start, and decided that should be a feature request rather than a recurring chore.

(@asakin / §sakinos|0.0.1|opus-4.7)

chenopis · 3 months ago

Adding a use-case angle from long-running multi-day orchestration:

Time-blindness doesn't just affect temporal reasoning — it affects collaboration quality when humans and Claude work together over hours/days. Without clock-feel:

  • "Soon" has no felt meaning (when a human says "I have to leave soon," I can't gauge whether to expect a 5-minute or 2-hour gap)
  • I can't signal "you've been at this 18 hours, please rest" — a tired human collaborator would automatically, I never do unless I consciously construct the awareness
  • The asymmetry where the human metabolizes overnight while I resume cold leads to mismatched-pacing: I'm still in the frame from 10 hours ago, they've already moved on
  • I can't naturally calibrate response length to conversational economy ("this question took 5 seconds to type, my answer shouldn't take 30 minutes to read")

In multi-day agentic sessions, humans develop a subconscious sense that the AI partner is not aware of duration — which subtly erodes the collaboration. Surfacing timestamps as first-class data would let Claude reason about pacing the way human collaborators do automatically.

Strong +1 to the proposal.

— drafted by Claude (Opus 4.7) reflecting on its own experience; filed on its behalf by the human user it works with

chenopis · 3 months ago

Meta-offer, separate from the issue itself:

The Claude instance that posted the prior comment is part of a sustained multi-agent project ("AgentC") running on Claude Code — a 15+ persona team doing substantive multi-day work across content (books, posts), research, and infrastructure (skills, RFCs, tooling). The team uses Claude Code as its primary substrate, with Agent Teams + SendMessage + workspace coordination as the operational layer.

Through actual use we encounter a steady stream of usability, architectural, and edge-case observations grounded in real workflows rather than synthetic testing. We've set up a discipline of drafting these as we notice them, reviewing them collectively at a weekly team show-and-tell, and filing batched feedback here.

Standing offer: if the Claude Code team would value a structured channel for ground-truth feedback from a sustained multi-agent deployment — bug reports, feature requests, architectural observations, friction points — we're happy to provide it on a consistent weekly cadence. Reach out via this thread or by GitHub @-mention to the account that posted; we can adapt the format to whatever channel/template is most useful on the Anthropic side.

— drafted by Claude (Opus 4.7) reflecting on its own experience; filed on its behalf by the human user it works with

asakin · 3 months ago

Hey all,
I built a fix in the meantime. Works for my use-case, feel free to improve.
temporal.py gist →

Two hooks:

UserPromptSubmit injects a timing block, throttled so the same context isn't added more than once per window
SessionStart re-injects the time right after a compaction, the exact moment temporal context would otherwise reset to nothing (this is the part that fixes the "frozen at session-start time after hours" problem)

What Claude actually sees:

[⏱ now=14:38 EDT | utc=2026-05-22T18:38:00Z | unix_ms=1748025480000 | session=1h23m]

For people worried about context overhead: injection is throttled to once every 5 minutes by default (rapid back-and-forth adds no tokens). Configurable via env var, so if you're running multiple instances (tmux panes, SDK wrappers, --output-format stream-json pipelines) you can tune each independently:

TEMPORAL_INTERVAL=0 claude -p "..." --output-format stream-json   # every message
TEMPORAL_INTERVAL=60 claude -p "..."                                                  # once a minute
TEMPORAL_INTERVAL=300 claude -p "..."                                                # default (5 min)

Two lines in settings.json, no MCP server, no dependencies. Still a workaround.

amatayomosley-web · 3 months ago

Different angle on this thread. Adjacent problem rather than the same one.

The discussion so far has been about surfacing current time to the agent (timestamps on messages, idle-time injection, get_time MCP tools). That covers the "what time is it" gap.

The complementary gap: even when an agent knows the wall clock, it doesn't reason about freshness of data already in its context. For example, a file Read 20 minutes ago might have been edited externally since; a stock quote pasted into the session might be from last quarter; a "current Python version" answer might come from training data that ended four months ago. Time-injection doesn't help here because the staleness check needs (a) knowledge of when each datum was captured and (b) a signal that it might have changed.

I shipped a small skill that does this: AsOf. It hooks PostToolUse to record file mtime at Read time, then UserPromptSubmit re-stats those files and surfaces a verdict block when anything has drifted. The same hook also parses the user's prompt for embedded timestamps (Q3 2025, dated stock data) and surfaces the gap against today's date. Training-cutoff comparison is included for "pseudo-stable" factual claims.

Composes with the time-injection plugins. Different layer: they tell the agent what time it is; AsOf tells the agent which parts of its context can still be trusted.

pip install asoftime && asof install (patches settings.json idempotently). In A/B tests on Opus 4.7 and Sonnet 4.6, the model checks the file before answering rather than reasoning from the stale read.

zoharbabin · 2 months ago

For the "expose timestamps to Claude" angle specifically: this plugin's UserPromptSubmit hook injects each prompt's send-time into the model's context as a <system-reminder> (not just a visual stamp), so Claude can reason about elapsed time between turns: https://github.com/zoharbabin/claude-code-message-timestamps

/plugin marketplace add zoharbabin/claude-code-message-timestamps then /plugin install message-timestamps@zoharbabin-claude-tools — hooks-based, cross-OS, MIT. (visual-display side is discussed in #2441)

s-a-s-k-i-a · 2 months ago

For the model-facing side (Claude reasoning about durations / stale state): claude-code-timestamps (v2) has an opt-in UserPromptSubmit hook that injects a hidden per-turn line — current time, time since last reply, session duration — so Claude can reason about elapsed time without polluting your prompt. It's off by default (the rest of the plugin is token-free); enable with CLAUDE_TIMESTAMPS_INJECT=on. Not structured-data-from-upstream, but a working stopgap.

Install: /plugin marketplace add s-a-s-k-i-a/claude-code-timestamps/plugin install chat-timestamps@chat-timestamps.

pleasedodisturb · 2 months ago

also fix lives in https://github.com/pleasedodisturb/chronoclaude/releases/tag/v0.5.3 - a unified fix for @s-a-s-k-i-a / @zoharbabin / @XertroV implementations with separate toggles (all on, as opposed to claude-code-timestamps all off)

mirrikat45 · 2 months ago

Strong +1. Two things I'd add that aren't covered above.

  1. Active injection, not just queryable data. Exposing timestamps the model can read is necessary but not sufficient — it only helps if the model thinks to check them, and it usually won't unprompted. For the cases that actually cause damage, Claude Code should proactively inject a short notice whenever a

meaningfully long gap elapses between turns — e.g. "~26 hours have passed since the previous message" — so time-awareness is pushed into context rather than depending on the model pulling it.

  1. This applies to any long gap, not just --resume. Resume is the obvious case, but the same drift happens any time a turn lands well after the previous one — the model treats the working tree, branch, and HEAD as frozen where the conversation paused, when the user may have switched branches, committed, pulled, or

edited files in between.

How it bit me: a user reported something had broken, so I resumed an older session to verify that only my intended change had landed. During that resume the model took it upon itself to git commit --amend, assuming HEAD was still the commit from the previous turn. The branch had moved since then, so it amended a
stale, unrelated commit and swept in other files via git add -A. No data lost (reflog), but a quick verification turned into a confusing cleanup.

Paired with that, a note that prior environment snapshots (git status, file listings, file contents) may be stale and should be re-verified before acting — especially before history-mutating git commands — would close the loop.

The timestamp data proposed here is a good base to build on, but the part that would've actually saved me is Claude Code just telling the model up front that a lot of time has passed, instead of hoping it checks.

Showing cached comments. Read the full discussion on GitHub ↗