-
-
Notifications
You must be signed in to change notification settings - Fork 317
fix(amp,opencode,codex,pi): add dateFormatter to prevent date truncation #788
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…rmatting Move formatDateCompact from ccusage to the shared terminal package so all apps can use consistent date formatting in tables. This function formats dates as "YYYY\nMM-DD" for compact table display when terminal width is limited. The function handles both YYYY-MM-DD and ISO timestamp formats, with optional timezone and locale parameters.
Replace local formatDateCompact implementation with a re-export from @ccusage/terminal/table. This removes code duplication and ensures consistent date formatting across all packages. Move related tests to the terminal package where the implementation now lives.
Add dateFormatter option to ResponsiveTable in all CLI apps to ensure dates are properly formatted when terminal width is narrow. Previously, dates were being truncated because the dateFormatter was not configured. This change imports formatDateCompact from @ccusage/terminal and passes it to the table configuration, matching the behaviour of ccusage. Affected commands: - amp: daily, monthly, session - opencode: daily, monthly, session, weekly - codex: daily, monthly, session - pi: daily, monthly, session
📝 WalkthroughWalkthroughThe PR adds a new Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~15 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
ccusage-guide | bd48861 | Jan 09 2026, 01:21 PM |
@ccusage/amp
ccusage
@ccusage/codex
@ccusage/mcp
@ccusage/opencode
@ccusage/pi
commit: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/opencode/src/commands/daily.ts (1)
1-15: SimplifydateFormatterand fix local import extensions for consistency.
- Line 138-139: Replace
dateFormatter: (dateStr: string) => formatDateCompact(dateStr)withdateFormatter: formatDateCompact(the signatures are compatible).- Lines 13-14: Add
.tsextensions to local imports ('../cost-utils.ts'and'../data-loader.ts') to match the project convention already used in other files.Proposed changes
-import { calculateCostForEntry } from '../cost-utils'; -import { loadOpenCodeMessages } from '../data-loader'; +import { calculateCostForEntry } from '../cost-utils.ts'; +import { loadOpenCodeMessages } from '../data-loader.ts';compactThreshold: 100, forceCompact: Boolean(ctx.values.compact), style: { head: ['cyan'] }, - dateFormatter: (dateStr: string) => formatDateCompact(dateStr), + dateFormatter: formatDateCompact, });apps/pi/src/commands/daily.ts (1)
2-9: Pass--timezoneparameter toformatDateCompactin table rendering.The
--timezone/-zCLI option is defined (lines 31–35) and passed to the data loader (line 56), but the table formatter ignores it.formatDateCompactaccepts and respects a timezone parameter, so pass it here for the date display to honor the user's timezone choice.Proposed change
const table = createUsageReportTable({ firstColumnName: 'Date', - dateFormatter: (dateStr: string) => formatDateCompact(dateStr), + dateFormatter: (dateStr: string) => formatDateCompact(dateStr, ctx.values.timezone), });Note: This same issue exists in
monthly.tsandsession.ts—all three should be updated consistently.
🤖 Fix all issues with AI agents
In @packages/terminal/src/table.ts:
- Around line 31-54: Update the JSDoc for formatDateCompact to match the actual
default locale used in code: replace the incorrect "defaults to sv-SE for
YYYY-MM-DD format" text with a statement that it defaults to DEFAULT_LOCALE
(en-CA) or explicitly "defaults to en-CA" so the comment reflects the
implementation using DEFAULT_LOCALE.
🧹 Nitpick comments (5)
apps/amp/src/commands/daily.ts (1)
2-9: UsedateFormatter: formatDateCompact(no need for a wrapper).
formatDateCompactalready matches(dateStr: string) => string, so you can pass it directly.Proposed change
compactThreshold: 100, forceCompact: Boolean(ctx.values.compact), style: { head: ['cyan'] }, - dateFormatter: (dateStr: string) => formatDateCompact(dateStr), + dateFormatter: formatDateCompact, });Also applies to: 146-165
apps/opencode/src/commands/monthly.ts (1)
138-138: Correct implementation with an optional simplification.The
dateFormatteroption is correctly wired to useformatDateCompact, achieving the PR objective of preventing date truncation in narrow terminals.♻️ Optional: Simplify arrow function wrapper
Since
formatDateCompactalready matches the expected signature, you can pass it directly:- dateFormatter: (dateStr: string) => formatDateCompact(dateStr), + dateFormatter: formatDateCompact,This same simplification applies to all similar usages across the other command files in this PR (amp/session.ts, codex/session.ts, codex/daily.ts, opencode/session.ts).
apps/pi/src/commands/monthly.ts (1)
104-104: Optional: Simplify the dateFormatter wrapper.The wrapper function
(dateStr: string) => formatDateCompact(dateStr)is redundant sinceformatDateCompactalready has the same signature. You can pass the function directly.♻️ Simplify to direct reference
- dateFormatter: (dateStr: string) => formatDateCompact(dateStr), + dateFormatter: formatDateCompact,apps/codex/src/commands/monthly.ts (1)
133-133: Optional: Simplify the dateFormatter wrapper.The wrapper function is redundant. You can pass
formatDateCompactdirectly since it already matches the expected signature.♻️ Simplify to direct reference
- dateFormatter: (dateStr: string) => formatDateCompact(dateStr), + dateFormatter: formatDateCompact,apps/opencode/src/commands/weekly.ts (1)
163-163: Optional: Simplify the dateFormatter wrapper.The wrapper function is redundant and can be replaced with a direct reference to
formatDateCompact.♻️ Simplify to direct reference
- dateFormatter: (dateStr: string) => formatDateCompact(dateStr), + dateFormatter: formatDateCompact,
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (15)
apps/amp/src/commands/daily.tsapps/amp/src/commands/monthly.tsapps/amp/src/commands/session.tsapps/ccusage/src/_date-utils.tsapps/codex/src/commands/daily.tsapps/codex/src/commands/monthly.tsapps/codex/src/commands/session.tsapps/opencode/src/commands/daily.tsapps/opencode/src/commands/monthly.tsapps/opencode/src/commands/session.tsapps/opencode/src/commands/weekly.tsapps/pi/src/commands/daily.tsapps/pi/src/commands/monthly.tsapps/pi/src/commands/session.tspackages/terminal/src/table.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.ts: Import conventions: Use.tsextensions for local file imports (e.g.,import { foo } from './utils.ts')
Use ESLint for linting and formatting with tab indentation and double quotes
No console.log allowed except where explicitly disabled with eslint-disable
Use camelCase for variable names (e.g.,usageDataSchema,modelBreakdownSchema)
Use PascalCase for type names (e.g.,UsageData,ModelBreakdown)
Use UPPER_SNAKE_CASE for constants (e.g.,DEFAULT_CLAUDE_CODE_PATH)
Only export constants, functions, and types that are actually used by other modules - do not export internal/private constants used only within the same file
Prefer @praha/byethrow Result type over traditional try-catch for functional error handling
UseResult.try()for wrapping operations that may throw (JSON parsing, etc.)
UseResult.isFailure()for checking errors (more readable than!Result.isSuccess())
Use early return pattern (if (Result.isFailure(result)) continue;) instead of ternary operators with Result types
NEVER useawait import()dynamic imports anywhere in the codebase - this causes tree-shaking issues
Do not use console.log - use logger.ts instead
Vitest globals (describe,it,expect) are available automatically without imports in test blocks
NEVER useawait import()dynamic imports in vitest test blocks - this is particularly problematic for test execution
All test files must use current Claude 4 models (claude-sonnet-4-20250514, claude-opus-4-20250514), not outdated Claude 3 models
Model names in tests must exactly match LiteLLM's pricing database entries
Files:
apps/codex/src/commands/session.tsapps/amp/src/commands/monthly.tsapps/opencode/src/commands/monthly.tsapps/pi/src/commands/session.tsapps/pi/src/commands/daily.tsapps/amp/src/commands/daily.tsapps/opencode/src/commands/session.tsapps/codex/src/commands/monthly.tspackages/terminal/src/table.tsapps/ccusage/src/_date-utils.tsapps/amp/src/commands/session.tsapps/opencode/src/commands/daily.tsapps/pi/src/commands/monthly.tsapps/codex/src/commands/daily.tsapps/opencode/src/commands/weekly.ts
apps/amp/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (apps/amp/CLAUDE.md)
NEVER use await import() dynamic imports anywhere, especially in test blocks in Amp CLI
Files:
apps/amp/src/commands/monthly.tsapps/amp/src/commands/daily.tsapps/amp/src/commands/session.ts
apps/opencode/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (apps/opencode/CLAUDE.md)
apps/opencode/**/*.{ts,tsx,js,jsx}: Message structure must includetokens.input,tokens.output,tokens.cache.read, andtokens.cache.writefields
Map token fields:inputTokens←tokens.input,outputTokens←tokens.output,cacheReadInputTokens←tokens.cache.read,cacheCreationInputTokens←tokens.cache.write
Calculate costs using model pricing data when pre-calculatedcostfield is not present in OpenCode messages
Reuse shared packages (@ccusage/terminal,@ccusage/internal) wherever possible
Data discovery relies onOPENCODE_DATA_DIRenvironment variable with default path~/.local/share/opencode
Place all vitest blocks alongside implementation files viaif (import.meta.vitest != null)guards
apps/opencode/**/*.{ts,tsx,js,jsx}: Use meaningful variable and function names that clearly describe their purpose
Add JSDoc comments to exported functions and classes to document their purpose, parameters, and return values
Prefer const for variables that won't be reassigned; use let for variables that will be reassigned
Use immutable data structures and avoid mutation where possible
Files:
apps/opencode/src/commands/monthly.tsapps/opencode/src/commands/session.tsapps/opencode/src/commands/daily.tsapps/opencode/src/commands/weekly.ts
apps/opencode/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/opencode/AGENTS.md)
Avoid using
anytype in TypeScript; use explicit types or generics instead
Files:
apps/opencode/src/commands/monthly.tsapps/opencode/src/commands/session.tsapps/opencode/src/commands/daily.tsapps/opencode/src/commands/weekly.ts
apps/pi/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/pi/CLAUDE.md)
apps/pi/src/**/*.{ts,tsx}: Prefer@praha/byethrow Resulttype over try-catch for error handling
Use.tsextensions for local imports
Only export what's actually used from modules
NEVER useawait import()dynamic imports anywhere in the codebase
Files:
apps/pi/src/commands/session.tsapps/pi/src/commands/daily.tsapps/pi/src/commands/monthly.ts
apps/ccusage/src/**/*.ts
📄 CodeRabbit inference engine (apps/ccusage/CLAUDE.md)
apps/ccusage/src/**/*.ts: Write tests in-source usingif (import.meta.vitest != null)blocks instead of separate test files
Use Vitest globals (describe,it,expect) without imports in test blocks
In tests, use current Claude 4 models (sonnet-4, opus-4)
Usefs-fixturewithcreateFixture()to simulate Claude data in tests
Only export symbols that are actually used by other modules
Do not use console.log; use the logger utilities fromsrc/logger.tsinstead
Files:
apps/ccusage/src/_date-utils.ts
apps/ccusage/**/*.ts
📄 CodeRabbit inference engine (apps/ccusage/CLAUDE.md)
apps/ccusage/**/*.ts: NEVER useawait import()dynamic imports anywhere (especially in tests)
Prefer@praha/byethrowResult type for error handling instead of try-catch
Use.tsextensions for local imports (e.g.,import { foo } from './utils.ts')
Files:
apps/ccusage/src/_date-utils.ts
**/_*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Use underscore prefix for internal files (e.g.,
_types.ts,_utils.ts,_consts.ts)
Files:
apps/ccusage/src/_date-utils.ts
🧠 Learnings (13)
📚 Learning: 2025-09-18T16:06:37.474Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/ccusage/CLAUDE.md:0-0
Timestamp: 2025-09-18T16:06:37.474Z
Learning: Applies to apps/ccusage/**/*.ts : Use `.ts` extensions for local imports (e.g., `import { foo } from './utils.ts'`)
Applied to files:
apps/pi/src/commands/session.tsapps/ccusage/src/_date-utils.ts
📚 Learning: 2026-01-09T12:35:27.240Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/amp/CLAUDE.md:0-0
Timestamp: 2026-01-09T12:35:27.240Z
Learning: Reuse shared packages ccusage/terminal and ccusage/internal wherever possible in Amp CLI
Applied to files:
apps/amp/src/commands/daily.tsapps/ccusage/src/_date-utils.ts
📚 Learning: 2026-01-09T11:07:17.610Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/opencode/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:17.610Z
Learning: Applies to apps/opencode/**/*.{ts,tsx,js,jsx} : Reuse shared packages (`ccusage/terminal`, `ccusage/internal`) wherever possible
Applied to files:
apps/ccusage/src/_date-utils.ts
📚 Learning: 2025-09-18T16:06:37.474Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/ccusage/CLAUDE.md:0-0
Timestamp: 2025-09-18T16:06:37.474Z
Learning: Applies to apps/ccusage/src/**/*.ts : Only export symbols that are actually used by other modules
Applied to files:
apps/ccusage/src/_date-utils.ts
📚 Learning: 2025-09-17T18:29:15.764Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/mcp/CLAUDE.md:0-0
Timestamp: 2025-09-17T18:29:15.764Z
Learning: Applies to apps/mcp/**/*.ts : Only export what is actually used
Applied to files:
apps/ccusage/src/_date-utils.ts
📚 Learning: 2025-09-18T16:06:37.474Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/ccusage/CLAUDE.md:0-0
Timestamp: 2025-09-18T16:06:37.474Z
Learning: Applies to apps/ccusage/src/**/*.ts : Do not use console.log; use the logger utilities from `src/logger.ts` instead
Applied to files:
apps/ccusage/src/_date-utils.ts
📚 Learning: 2025-09-18T16:06:37.474Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/ccusage/CLAUDE.md:0-0
Timestamp: 2025-09-18T16:06:37.474Z
Learning: Applies to apps/ccusage/src/**/*.ts : Write tests in-source using `if (import.meta.vitest != null)` blocks instead of separate test files
Applied to files:
apps/ccusage/src/_date-utils.ts
📚 Learning: 2026-01-09T12:22:39.520Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-09T12:22:39.520Z
Learning: Applies to **/*.ts : Only export constants, functions, and types that are actually used by other modules - do not export internal/private constants used only within the same file
Applied to files:
apps/ccusage/src/_date-utils.ts
📚 Learning: 2026-01-09T12:07:00.515Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/pi/CLAUDE.md:0-0
Timestamp: 2026-01-09T12:07:00.515Z
Learning: Applies to apps/pi/src/**/*.{ts,tsx} : Only export what's actually used from modules
Applied to files:
apps/ccusage/src/_date-utils.ts
📚 Learning: 2025-09-18T16:06:37.474Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/ccusage/CLAUDE.md:0-0
Timestamp: 2025-09-18T16:06:37.474Z
Learning: Applies to apps/ccusage/src/**/*.ts : Use Vitest globals (`describe`, `it`, `expect`) without imports in test blocks
Applied to files:
apps/ccusage/src/_date-utils.ts
📚 Learning: 2026-01-09T11:07:17.610Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/opencode/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:17.610Z
Learning: Applies to apps/opencode/**/*.test.{ts,tsx,js,jsx} : Vitest globals are enabled - use `describe`, `it`, `expect` directly without imports
Applied to files:
apps/ccusage/src/_date-utils.ts
📚 Learning: 2025-09-17T18:29:15.764Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/mcp/CLAUDE.md:0-0
Timestamp: 2025-09-17T18:29:15.764Z
Learning: Applies to apps/mcp/**/*.{test,spec}.ts : Vitest globals enabled: use `describe`, `it`, `expect` directly without importing them
Applied to files:
apps/ccusage/src/_date-utils.ts
📚 Learning: 2026-01-09T11:07:17.610Z
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/opencode/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:17.610Z
Learning: Applies to apps/opencode/**/*.test.{ts,tsx,js,jsx} : Use `fs-fixture` with `using` statement to ensure cleanup in tests
Applied to files:
apps/ccusage/src/_date-utils.ts
🧬 Code graph analysis (3)
apps/pi/src/commands/session.ts (1)
packages/terminal/src/table.ts (1)
formatDateCompact(38-54)
apps/pi/src/commands/daily.ts (1)
packages/terminal/src/table.ts (1)
formatDateCompact(38-54)
apps/pi/src/commands/monthly.ts (1)
packages/terminal/src/table.ts (1)
formatDateCompact(38-54)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Workers Builds: ccusage-guide
🔇 Additional comments (14)
apps/amp/src/commands/monthly.ts (1)
2-9: Remove unnecessarydateFormatteroption—it won't apply toYYYY-MMmonth values.The
ResponsiveTableappliesdateFormatteronly to first-column cells matchingYYYY-MM-DDformat. Sincedata.monthisYYYY-MM(line 169), the formatter is never invoked. Remove the unuseddateFormatteroption at line 164 to clarify intent.Likely an incorrect or invalid review comment.
apps/pi/src/commands/session.ts (1)
3-10: Review comment is invalid—dateFormatterwill not crash on session names due to proper validation.The code safely applies
dateFormatteronly to cells in the first column that match the date pattern^\d{4}-\d{2}-\d{2}$(viaisDateString()check). Session names like truncated project paths will not match this pattern and will be skipped. No crash risk exists.Likely an incorrect or invalid review comment.
apps/opencode/src/commands/monthly.ts (1)
5-5: LGTM! Import follows shared package conventions.The
formatDateCompactimport from the shared@ccusage/terminal/tablepackage is correct and aligns with the coding guideline to reuse shared packages.apps/amp/src/commands/session.ts (1)
5-5: LGTM! Consistent implementation of date formatting.The import and usage of
formatDateCompactare correct and follow the same pattern as other commands in this PR, enabling consistent date display in narrow terminals.Also applies to: 173-173
apps/codex/src/commands/session.ts (1)
5-5: LGTM! Date formatter correctly integrated.The
formatDateCompactimport anddateFormatteroption are correctly implemented, aligning with the PR objective to prevent date truncation in the session command's table output.Also applies to: 153-153
apps/opencode/src/commands/session.ts (1)
5-5: LGTM! Consistent date formatting integration.The
formatDateCompactimport and usage are correct and follow the established pattern across the codebase for preventing date truncation in table displays.Also applies to: 156-156
apps/codex/src/commands/daily.ts (1)
5-5: LGTM! Date formatter properly configured.The import and usage of
formatDateCompactare correct and consistent with the other command files in this PR, successfully addressing the date truncation issue in narrow terminals.Also applies to: 131-131
apps/pi/src/commands/monthly.ts (1)
5-5: LGTM: Import added correctly.The import follows the project's pattern of reusing shared packages from
@ccusage/terminal.apps/codex/src/commands/monthly.ts (1)
5-5: LGTM: Import added correctly.The import follows the project's pattern of reusing shared packages.
apps/opencode/src/commands/weekly.ts (1)
5-5: LGTM: Import added correctly.The import follows the established pattern.
packages/terminal/src/table.ts (2)
7-29: LGTM: Well-structured date formatting helpers.The DEFAULT_LOCALE and createDatePartsFormatter helper are well-designed with clear documentation.
1082-1107: LGTM: Comprehensive test coverage.The tests cover the key scenarios including timezone handling, format variations, and default locale behavior.
apps/ccusage/src/_date-utils.ts (2)
13-14: LGTM: Clean re-export pattern.The re-export of
formatDateCompactfrom the shared terminal package eliminates code duplication and centralizes the implementation. This aligns with the project's guideline to reuse shared packages wherever possible.Based on learnings, reusing shared packages is a documented best practice for this codebase.
159-159: LGTM: Tests properly relocated.The comment correctly documents that tests for
formatDateCompactare now maintained in the source package, avoiding test duplication.
| /** | ||
| * Formats a date string to compact format with year on first line and month-day on second | ||
| * @param dateStr - Input date string (YYYY-MM-DD or ISO timestamp) | ||
| * @param timezone - Timezone to use for formatting (pass undefined to use system timezone) | ||
| * @param locale - Locale to use for formatting (defaults to sv-SE for YYYY-MM-DD format) | ||
| * @returns Formatted date string with newline separator (YYYY\nMM-DD) | ||
| */ | ||
| export function formatDateCompact(dateStr: string, timezone?: string, locale?: string): string { | ||
| // Check if input is in YYYY-MM-DD format | ||
| const isSimpleDateFormat = /^\d{4}-\d{2}-\d{2}$/.test(dateStr); | ||
| // For YYYY-MM-DD format, append T00:00:00 to parse as local date | ||
| // Without this, new Date('YYYY-MM-DD') interprets as UTC midnight | ||
| const date = isSimpleDateFormat | ||
| ? timezone != null | ||
| ? new Date(`${dateStr}T00:00:00Z`) | ||
| : new Date(`${dateStr}T00:00:00`) | ||
| : new Date(dateStr); | ||
| const formatter = createDatePartsFormatter(timezone, locale ?? DEFAULT_LOCALE); | ||
| const parts = formatter.formatToParts(date); | ||
| const year = parts.find((p) => p.type === 'year')?.value ?? ''; | ||
| const month = parts.find((p) => p.type === 'month')?.value ?? ''; | ||
| const day = parts.find((p) => p.type === 'day')?.value ?? ''; | ||
| return `${year}\n${month}-${day}`; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix JSDoc inconsistency.
Line 35 mentions "defaults to sv-SE for YYYY-MM-DD format" but the code actually uses DEFAULT_LOCALE which is en-CA. The implementation is correct, but the documentation is outdated.
📝 Fix the JSDoc comment
/**
* Formats a date string to compact format with year on first line and month-day on second
* @param dateStr - Input date string (YYYY-MM-DD or ISO timestamp)
* @param timezone - Timezone to use for formatting (pass undefined to use system timezone)
- * @param locale - Locale to use for formatting (defaults to sv-SE for YYYY-MM-DD format)
+ * @param locale - Locale to use for formatting (defaults to en-CA for YYYY-MM-DD format)
* @returns Formatted date string with newline separator (YYYY\nMM-DD)
*/
export function formatDateCompact(dateStr: string, timezone?: string, locale?: string): string {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| /** | |
| * Formats a date string to compact format with year on first line and month-day on second | |
| * @param dateStr - Input date string (YYYY-MM-DD or ISO timestamp) | |
| * @param timezone - Timezone to use for formatting (pass undefined to use system timezone) | |
| * @param locale - Locale to use for formatting (defaults to sv-SE for YYYY-MM-DD format) | |
| * @returns Formatted date string with newline separator (YYYY\nMM-DD) | |
| */ | |
| export function formatDateCompact(dateStr: string, timezone?: string, locale?: string): string { | |
| // Check if input is in YYYY-MM-DD format | |
| const isSimpleDateFormat = /^\d{4}-\d{2}-\d{2}$/.test(dateStr); | |
| // For YYYY-MM-DD format, append T00:00:00 to parse as local date | |
| // Without this, new Date('YYYY-MM-DD') interprets as UTC midnight | |
| const date = isSimpleDateFormat | |
| ? timezone != null | |
| ? new Date(`${dateStr}T00:00:00Z`) | |
| : new Date(`${dateStr}T00:00:00`) | |
| : new Date(dateStr); | |
| const formatter = createDatePartsFormatter(timezone, locale ?? DEFAULT_LOCALE); | |
| const parts = formatter.formatToParts(date); | |
| const year = parts.find((p) => p.type === 'year')?.value ?? ''; | |
| const month = parts.find((p) => p.type === 'month')?.value ?? ''; | |
| const day = parts.find((p) => p.type === 'day')?.value ?? ''; | |
| return `${year}\n${month}-${day}`; | |
| } | |
| /** | |
| * Formats a date string to compact format with year on first line and month-day on second | |
| * @param dateStr - Input date string (YYYY-MM-DD or ISO timestamp) | |
| * @param timezone - Timezone to use for formatting (pass undefined to use system timezone) | |
| * @param locale - Locale to use for formatting (defaults to en-CA for YYYY-MM-DD format) | |
| * @returns Formatted date string with newline separator (YYYY\nMM-DD) | |
| */ | |
| export function formatDateCompact(dateStr: string, timezone?: string, locale?: string): string { | |
| // Check if input is in YYYY-MM-DD format | |
| const isSimpleDateFormat = /^\d{4}-\d{2}-\d{2}$/.test(dateStr); | |
| // For YYYY-MM-DD format, append T00:00:00 to parse as local date | |
| // Without this, new Date('YYYY-MM-DD') interprets as UTC midnight | |
| const date = isSimpleDateFormat | |
| ? timezone != null | |
| ? new Date(`${dateStr}T00:00:00Z`) | |
| : new Date(`${dateStr}T00:00:00`) | |
| : new Date(dateStr); | |
| const formatter = createDatePartsFormatter(timezone, locale ?? DEFAULT_LOCALE); | |
| const parts = formatter.formatToParts(date); | |
| const year = parts.find((p) => p.type === 'year')?.value ?? ''; | |
| const month = parts.find((p) => p.type === 'month')?.value ?? ''; | |
| const day = parts.find((p) => p.type === 'day')?.value ?? ''; | |
| return `${year}\n${month}-${day}`; | |
| } |
🤖 Prompt for AI Agents
In @packages/terminal/src/table.ts around lines 31 - 54, Update the JSDoc for
formatDateCompact to match the actual default locale used in code: replace the
incorrect "defaults to sv-SE for YYYY-MM-DD format" text with a statement that
it defaults to DEFAULT_LOCALE (en-CA) or explicitly "defaults to en-CA" so the
comment reflects the implementation using DEFAULT_LOCALE.
Summary
Fix date truncation in amp, opencode, codex, and pi CLI apps by adding
dateFormattertoResponsiveTableconfiguration.What Changed
formatDateCompactfunction for consistent date formatting across all packagesformatDateCompactfrom the shared terminal package (removes duplication)dateFormatterin all table views to properly format dates when terminal is narrowWhy
Previously, ccusage formatted dates nicely in tables, but amp, opencode, codex, and pi apps were showing truncated dates because they weren't using the
dateFormatteroption. This change ensures all CLI apps have consistent date display behaviour.Test Plan
pnpm run formatpassespnpm typecheckpassespnpm run testpasses (all 337 tests)Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.