Repository navigation
claude session ignores --since/--until in totals (codex session does not) #1609
Description
Activity
pullfrog commented
on Aug 16, 2026 pullfrogboton Aug 16, 2026 – with PullfrogContributorMore actionsIssue #1609 is actionable and reproducible from the current code. The focused Claude path in
rust/crates/ccusage/src/commands/mod.rsloads and aggregates every entry, then filters completed rows usinglast_activityas an RFC3339 string; this cannot scope totals, rejects the inclusive--untilboundary day, and ignores the requested timezone. The unified Claude path inrust/crates/ccusage-adapter-all/src/loader.rshas the same post-aggregation behavior.Plan
- Change focused Claude session processing in
rust/crates/ccusage/src/commands/mod.rsto apply the existingccusage_adapter_common::filter_loaded_entries_by_datehelper to loaded entries before session grouping. Remove the row-levellast_activitydate comparison. Apply the same entry filtering in the--idlookup path so focused session detail obeys the date window as well. - Change the unified Claude session branch in
rust/crates/ccusage-adapter-all/src/loader.rsto filter ClaudeLoadedEntryvalues beforesummarize_entry_sessions. Keep the separate behavior for other sources that use the shared session-summary helper unless their semantics are explicitly changed by a follow-up. - Add fixture-backed regression coverage for a Claude session spanning multiple dates. Assert that
--sinceand--untilchange token and cost totals, both boundary dates are inclusive, entries outside the window are excluded, and a non-UTC timezone determines the entry date. Cover both focused Claude session output and unified session rows so the two command surfaces stay consistent. - Add coverage for focused
--idlookup with a date window, including the no-in-range-entries result, and preserve deduplication, model breakdowns, session identity, and lifetime behavior when no bounds are supplied. - Audit
docs/guide/session-reports.mdand the Claude session guide wording. Update the documented semantics to explain that date bounds select usage entries and scope session totals, then run the focused Rust tests plus the repository’s standard format, lint, and check recipes.
Acceptance criteria
ccusage claude session --since/--untilreports totals calculated only from entries whose localized date is inside the inclusive window.--until YYYYMMDDincludes entries onYYYYMMDD, including the last activity boundary.--timezoneaffects date inclusion consistently with daily reports.ccusage sessionproduces the same Claude session totals for the same window.- Unbounded session reports remain unchanged, and Codex session behavior remains unchanged.
No implementation or tests were started in this planning run.
Task list (3/3 completed)
- Inspect issue
claude sessionignores --since/--until in totals (codex session does not) #1609 details and discussion - Trace Claude and Codex session date filtering and tests
- Post an actionable implementation plan or analysis
|⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to@v0or keep the SHA fresh with Dependabot | Implement plan ➔ | View workflow run | via Pullfrog | UsingGPT Luna(free via Pullfrog for OSS) | 𝕏- Change focused Claude session processing in
github-actions commented
on Aug 16, 2026 on Aug 16, 2026 – with GitHub ActionsContributorMore actionsThis issue was auto-closed. Issues from new contributors are auto-closed by default.
Maintainers review auto-closed issues and reopen worthwhile ones. Issues that do not meet the quality bar in CONTRIBUTING.md may not be reopened or receive a reply.
Keep the issue short, concrete, and written in your own voice.
If a maintainer replies
lgtmi, your future issues will stay open. If a maintainer replieslgtm, your future issues and PRs will stay open.See CONTRIBUTING.md.
@pullfrog Triage this issue using the repository standing issue-triage instructions. Inspect the full issue body, comments, current main branch, and related issues or pull requests. Choose exactly one priority label. If the issue is clearly unresolved and is priority:critical or priority:high with safe and well-scoped requirements, implement it and open a focused pull request. Otherwise, only triage it. Keep the explanation short and use simple English.
Reacted by pullfrog- addedpriority:highHigh user impact or an important regression.High user impact or an important regression.
on Aug 27, 2026 pullfrog commented
on Aug 27, 2026 pullfrogboton Aug 27, 2026 – with PullfrogContributorMore actionsPriority:
priority:high. This is a clear, reproducible bug in core usage totals: bounded Claude session reports can show lifetime cost and tokens, which is misleading for budgeting. The issue is unresolved onmain.I prepared commit
c7c305ewith the focused fix, regression tests, and documentation updates. The affected tests, clippy, and formatting checks pass, but the PR could not be opened becausegit pushwas denied with HTTP 403 forgithub-actions[bot]; the PR attempt then failed because the branch was not available remotely. |⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to@v0or keep the SHA fresh with Dependabot | View workflow run | via Pullfrog | UsingGPT Luna(free via Pullfrog for OSS) | 𝕏github-actions commented
on Aug 28, 2026 on Aug 28, 2026 – with GitHub ActionsContributorMore actionsPullfrog triage: priority:high
A maintainer explicitly requested an implementation attempt. Clear, reproducible, repository-scoped bug with a detailed root cause, expected behavior, and regression coverage scope. The issue remains unresolved, and the existing discussion indicates a safe focused fix was prepared but not published.
Decision: kept open; Pullfrog will attempt a focused implementation PR.
Historical audit: this discussion was auto-closed by the legacy contributor gate. That closure did not assess technical importance.
Audit result: resolved. A later merged change or the current
mainimplementation covers this request. This item is kept for history and does not need to be reopened.- addedtriage:resolvedResolved by a later change or current implementation.Resolved by a later change or current implementation.
on Aug 31, 2026

Summary
ccusage claude sessionaccepts--since/--untilbut the date window neverreaches the numbers. The flags only decide whether a session row is shown at
all; every row still reports the session's lifetime totals.
ccusage codex sessionscopes the same flags correctly, so the two providersdisagree under identical arguments.
This is silent and misleading: the row appears under a date filter, so the
figure reads as "usage in this window" when it is actually "usage since the
session was created". For a long-lived session the two differ by an order of
magnitude.
Three defects fall out of one root cause (details below).
Environment
npx ccusage@latest)49ad744ccb0a1a1b167a2b6dfa6bbcc9ffe9423fDefect A —
claude sessiontotals ignore the date windowSession
ef018fb9,firstActivity2026-08-04,lastActivity2026-08-14.Only
--sincevaries;--timezone UTCthroughout:--since--since 2026-08-14excludes ten days of activity, yet nothing moves.Not session-specific. Session
8fe7ee09,firstActivity2026-08-12,lastActivity2026-08-14:--sinceThe same test against
codex session(session019ee83f) scopes correctly:--sinceDefect B —
--untilis off by one daySame session,
lastActivity=2026-08-14T09:38:56.467Z,--timezone UTC:--until 2026-08-13--until 2026-08-14--until 2026-08-15--since 2026-08-14--since 2026-08-15--untilis documented as inclusive, so--until 2026-08-14should keep asession whose last activity is on 2026-08-14. The
--sinceboundary iscorrect; only
--untilis wrong.Same class as #1390, which was fixed for the pi provider.
Defect C —
--timezonedoes not apply to the session filterThe session filter compares against a UTC timestamp regardless of
--timezone, so the flag has no effect on which sessions are selected.Root cause
All three follow from one filter block.
rust/crates/ccusage/src/commands/mod.rs:172-188:This is the same shape as the daily filter in
rust/crates/ccusage-adapter-all/src/loader.rs:614-623:The only difference is the field read:
row.dateversusrow.last_activity.That single substitution breaks three assumptions at once.
A — wrong layer. In the daily report a row is a day, so retaining rows is
equivalent to filtering by date. In the session report a row is an entire
session, so retaining rows can only include or exclude a session whole. The
filter runs at
commands/mod.rs:172, after aggregation completes at lines168-171, and
load_entriesat line 152 applies no date bound — the Claudeadapter contains no reference to
sinceoruntilanywhere(
rust/adapters/claude/src/). By the time the filter runs, the lifetime totalsare already computed.
B — wrong granularity.
row.dateis a plainYYYY-MM-DD, so.replace('-', "")yields20260814, which compares correctly against thenormalized bound.
row.last_activityis a full RFC3339 timestamp(
ccusage-core/src/summary.rs:156→format_rfc3339_millis), so the same.replaceyields20260814T09:38:56.467Z. String-compared against20260814:The trailing time component makes the value always greater than the bare date
for the same day, so
--untilon the boundary day always fails. The>=sideis unaffected, which is why only
--untilis off.C — wrong timezone.
format_rfc3339_millis(
ccusage-core/src/date_utils.rs:344) starts withtimestamp.utc_parts()andis UTC-only, whereas the daily path formats
row.datethroughformat_datewith
shared.timezone. So the session filter silently ignores--timezone.For contrast, the Codex adapter filters during parsing and aggregation
(
rust/adapters/codex/src/aggregate.rs,parser.rs) rather than after, whichis why
codex sessionscopes correctly.Suggested fix
Push the date window down to entry loading / aggregation for the Claude path,
matching the Codex adapter. That fixes A, B and C together.
If a narrower fix is preferred, B and C can be addressed on their own by
truncating
last_activityto a date and formatting it withshared.timezonebefore comparing — but A would remain, and A is the one that produces wrong
numbers rather than a wrong row set.
Happy to test a patch.