Skip to content

Conversation

@ben-vargas
Copy link
Contributor

@ben-vargas ben-vargas commented Aug 4, 2025

Summary

This PR fixes an issue where usage data was being grouped by UTC date boundaries instead of the user's local timezone, causing data to appear on incorrect dates.

Fixes #413
Caused by #409

Problem

When using ccusage, usage data was being grouped incorrectly based on UTC time rather than the user's local timezone. This caused confusing results where:

  • Usage at 20:00 local time (MDT) would appear on the next day's report
  • Daily summaries didn't align with when users actually used Claude Code
  • Users in timezones behind UTC would see their evening usage shifted to the following day

Example

A user in MDT (UTC-6) using Claude Code at 8:00 PM on August 3rd would see that usage reported as August 4th, because 8:00 PM MDT is 2:00 AM UTC the next day.

Solution

Removed the hardcoded timeZone: 'UTC' configuration from the Intl.DateTimeFormat instances in data-loader.ts. This allows the date formatters to:

  1. Use the system's local timezone by default
  2. Respect the TZ environment variable if users want to override it
  3. Group usage data by local date boundaries as users would expect

Changes

  • Removed timeZone: 'UTC' from dateFormatter
  • Removed timeZone: 'UTC' from datePartsFormatter
  • Updated comment to reflect local timezone usage

Testing

  • All 253 existing tests pass
  • Verified that usage data now groups correctly by local date
  • Confirmed that the TZ environment variable can still override timezone if needed
  • Linting and type checking pass without issues

Backward Compatibility

This change makes the date grouping more intuitive and correct for users. The data itself is unchanged - only the grouping/display is affected. Users who need UTC grouping can still achieve it by setting TZ=UTC.

Summary by CodeRabbit

  • Bug Fixes
    • Dates are now displayed and grouped according to your local timezone instead of UTC, providing a more intuitive experience for users in different regions.

The date formatters were using UTC timezone which caused usage data to be
grouped incorrectly. For example, usage at 20:00 local time would appear
on the next day if the local timezone was behind UTC.

This regression was introduced in PR #409 (commit f7c5251) which added
explicit UTC timezone to the Intl.DateTimeFormat configuration.

The fix removes the hardcoded 'timeZone: UTC' option, allowing the
formatters to respect the system's local timezone or the TZ environment
variable if set.

Changes:
- Remove 'timeZone: UTC' from dateFormatter
- Remove 'timeZone: UTC' from datePartsFormatter
- Update comment to reflect local timezone usage

This ensures usage data is grouped by the user's local date boundaries
rather than UTC date boundaries.
@coderabbitai
Copy link

coderabbitai bot commented Aug 4, 2025

Walkthrough

The change removes the explicit 'UTC' timezone setting from two Intl.DateTimeFormat instances in src/data-loader.ts. As a result, date formatting and grouping now use the local timezone by default instead of UTC. No other logic or exported declarations are modified.

Changes

Cohort / File(s) Change Summary
Date Formatter Timezone Update
src/data-loader.ts
Removed explicit timeZone: 'UTC' from Intl.DateTimeFormat instances; now defaults to local timezone.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant DataLoader
    participant Intl.DateTimeFormat

    User->>DataLoader: Request data
    DataLoader->>Intl.DateTimeFormat: Format date (local timezone)
    Intl.DateTimeFormat-->>DataLoader: Formatted date string (local timezone)
    DataLoader-->>User: Return data with local-formatted dates
Loading

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~2 minutes

Assessment against linked issues

Objective Addressed Explanation
Use local timezone for date formatting and grouping instead of UTC (#413)

Assessment against linked issues: Out-of-scope changes

No out-of-scope changes found.

Possibly related PRs

Suggested reviewers

  • ryoppippi

Poem

A hop and a skip through the code I go,
Turning UTC to local, let the right dates show!
No more confusion, the time is just right—
Mountain or Eastern, day or night.
With paws on the keyboard, I fix with delight,
Now your dates and your data are perfectly bright!
🐇✨

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary of Changes

Hello @ben-vargas, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

I've addressed an issue where usage data was being grouped incorrectly based on UTC time, rather than the user's local timezone. This was causing data to appear on the wrong dates for users, especially those in timezones behind UTC. My solution involved removing the explicit timeZone: 'UTC' setting from the Intl.DateTimeFormat instances in data-loader.ts, which now allows the system to default to the user's local timezone for date grouping. This change significantly improves the accuracy and user-friendliness of the usage reports.

Highlights

  • Incorrect Date Grouping: Usage data was being incorrectly grouped by UTC date boundaries instead of the user's local timezone, leading to confusing and inaccurate reports where usage appeared on the wrong day.
  • Timezone Configuration Change: The hardcoded timeZone: 'UTC' configuration was removed from Intl.DateTimeFormat instances within data-loader.ts.
  • Improved User Experience: This change ensures that usage data is now grouped according to the user's local date boundaries, providing a more intuitive and accurate representation of their activity.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments or fill out our survey to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request correctly addresses an issue where usage data was grouped by UTC dates instead of the user's local timezone. By removing the hardcoded timeZone: 'UTC' from the Intl.DateTimeFormat instances, the date formatting now correctly defaults to the system's local timezone. The changes are simple, targeted, and effectively resolve the problem described, making the usage reports more intuitive for users in different timezones. The approach is sound and I see no issues with the implementation.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/data-loader.ts (1)

542-546: Mirror the comment above datePartsFormatter

For consistency with the first formatter’s docblock, update the comment here to mention that the system’s local timezone (or $TZ) is used. Purely cosmetic but avoids confusion for future readers.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3165855 and ea9ecc0.

📒 Files selected for processing (1)
  • src/data-loader.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.{js,jsx,ts,tsx}: Lint code using ESLint MCP server (available via Claude Code tools)
Format code with ESLint (writes changes) using bun run format
No console.log allowed except where explicitly disabled with eslint-disable
Do not use console.log. Use logger.ts instead.

Files:

  • src/data-loader.ts
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Type check with TypeScript using bun typecheck

Files:

  • src/data-loader.ts
**/*.ts

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.ts: File paths always use Node.js path utilities for cross-platform compatibility
Use .ts extensions for local file imports (e.g., import { foo } from './utils.ts')
Prefer @praha/byethrow Result type over traditional try-catch for functional error handling
Use Result.try() for wrapping operations that may throw (JSON parsing, etc.)
Use Result.isFailure() for checking errors (more readable than !Result.isSuccess())
Use early return pattern (if (Result.isFailure(result)) continue;) instead of ternary operators
For async operations: create wrapper function with Result.try() then call it
Keep traditional try-catch only for: file I/O with complex error handling, legacy code that's hard to refactor
Always use Result.isFailure() and Result.isSuccess() type guards for better code clarity
Variables: start with lowercase (camelCase) - e.g., usageDataSchema, modelBreakdownSchema
Types: start with uppercase (PascalCase) - e.g., UsageData, ModelBreakdown
Constants: can use UPPER_SNAKE_CASE - e.g., DEFAULT_CLAUDE_CODE_PATH
Only export constants, functions, and types that are actually used by other modules
Internal/private constants that are only used within the same file should NOT be exported
Always check if a constant is used elsewhere before making it export const vs just const
All test files must use current Claude 4 models, not outdated Claude 3 models
Test coverage should include both Sonnet and Opus models for comprehensive validation
Model names in tests must exactly match LiteLLM's pricing database entries
When adding new model tests, verify the model exists in LiteLLM before implementation
Tests depend on real pricing data from LiteLLM - failures may indicate model availability issues
Dynamic imports using await import() should only be used within test blocks to avoid tree-shaking issues
Mock data is created using fs-fixture with createFixture() for Claude data directory simulation
In-source testing pattern: Tests are written...

Files:

  • src/data-loader.ts
🔇 Additional comments (1)
src/data-loader.ts (1)

520-526: Local-TZ dateFormatter works, but verify midnight-edge cases

Dropping the timeZone: 'UTC' flag means new Date('2024-01-01T00:00:00Z') will now be rendered as the previous day for users west of UTC (e.g. America/Los_Angeles).
That’s the intended behavioural change, but a couple of unit tests (Lines 1381-1385) still assert '2024-01-01' for that exact timestamp. They will now fail on CI runners whose $TZ is not UTC.

Please:

- expect(formatDate('2024-01-01T00:00:00Z')).toBe('2024-01-01');
+ // At UTC midnight the local calendar day may shift. Assert relative result.
+ expect(['2023-12-31', '2024-01-01']).toContain(formatDate('2024-01-01T00:00:00Z'));

(or use a noon timestamp like elsewhere).
This keeps the tests hermetic across time-zones while retaining the desired production behaviour.

Copy link
Owner

@ryoppippi ryoppippi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@ryoppippi ryoppippi merged commit 540f929 into ryoppippi:main Aug 4, 2025
3 checks passed
@ben-vargas ben-vargas deleted the fix-date-time-utc-issue branch August 9, 2025 20:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Wrong Date Being Used

2 participants