fix(date-range): avoid all-period month overflow

This commit is contained in:
ozymandiashh 2026-05-05 05:05:13 +03:00
parent 3dc3e32715
commit 9a258a8a99
4 changed files with 20 additions and 17 deletions

View file

@ -26,7 +26,7 @@ const PERIODS = [
{ id: 'week', label: '7 Days' },
{ id: '30days', label: '30 Days' },
{ id: 'month', label: 'Month' },
{ id: 'all', label: 'All Time' },
{ id: 'all', label: '6 Months' },
];
export default class CodeBurnPreferences extends ExtensionPreferences {

View file

@ -113,7 +113,7 @@ export function getDateRange(period: string): { range: DateRange; label: string
return { range: { start, end }, label: 'Last 30 Days' }
}
case 'all': {
const start = new Date(now.getFullYear(), now.getMonth() - ALL_TIME_MONTHS, now.getDate())
const start = new Date(now.getFullYear(), now.getMonth() - ALL_TIME_MONTHS, 1)
return { range: { start, end }, label: 'Last 6 months' }
}
default: {

View file

@ -13,7 +13,7 @@ import { dateKey } from './day-aggregator.js'
import { CompareView } from './compare.js'
import { getPlanUsageOrNull, type PlanUsage } from './plan-usage.js'
import { planDisplayName } from './plans.js'
import { getDateRange as getDateRangeShared, PERIODS, PERIOD_LABELS, type Period } from './cli-date.js'
import { getDateRange, PERIODS, PERIOD_LABELS, type Period } from './cli-date.js'
import { join } from 'path'
import { patchStdoutForWindows } from './ink-win.js'
@ -96,7 +96,7 @@ function gradientColor(pct: number): string {
}
function getPeriodRange(period: Period): { start: Date; end: Date } {
return getDateRangeShared(period).range
return getDateRange(period).range
}
type Layout = { dashWidth: number; wide: boolean; halfWidth: number; barWidth: number }

View file

@ -1,4 +1,4 @@
import { describe, it, expect } from 'vitest'
import { afterEach, describe, it, expect, vi } from 'vitest'
import {
getDateRange,
PERIODS,
@ -7,6 +7,10 @@ import {
type Period,
} from '../src/cli-date.js'
afterEach(() => {
vi.useRealTimers()
})
describe('getDateRange', () => {
it('"all" is bounded to the last 6 months, not epoch', () => {
const { range, label } = getDateRange('all')
@ -18,27 +22,26 @@ describe('getDateRange', () => {
// dashboard bug) or any pre-2000 date.
expect(range.start.getFullYear()).toBeGreaterThan(2000)
// Roughly 6 months back. Accept 5-7 months to absorb end-of-month
// clamping (e.g. on May 31, JS rolls Nov 31 -> Dec 1, shifting the
// computed month forward by one).
const monthsDiff =
(now.getFullYear() - range.start.getFullYear()) * 12 +
(now.getMonth() - range.start.getMonth())
expect(monthsDiff).toBeGreaterThanOrEqual(5)
expect(monthsDiff).toBeLessThanOrEqual(7)
expect(monthsDiff).toBe(6)
expect(range.start.getDate()).toBe(1)
// End is today, end of day.
expect(range.end.getHours()).toBe(23)
expect(range.end.getMinutes()).toBe(59)
})
it('CLI and dashboard agree on "all" semantics (no Date(0) drift)', () => {
const a = getDateRange('all')
const b = getDateRange('all')
expect(a.range.start.getTime()).toBe(b.range.start.getTime())
expect(a.label).toBe(b.label)
// Regression guard: must never silently fall back to epoch.
expect(a.range.start.getFullYear()).toBeGreaterThan(2000)
it('"all" does not overflow past the target month at end-of-month', () => {
vi.useFakeTimers()
vi.setSystemTime(new Date(2026, 7, 31, 12, 0, 0))
const { range } = getDateRange('all')
expect(range.start.getFullYear()).toBe(2026)
expect(range.start.getMonth()).toBe(1)
expect(range.start.getDate()).toBe(1)
})
it('"week" returns the last 7 days', () => {