fix(site): set spend today range to end of day (#26992)

Selecting Today in the AI spend usage date range picker sent an end date
rounded to the next hour, which made refreshed usage pages show stale
partial-day data.

This lets the shared date range picker keep its existing next-hour
default for template insights while the spend usage and drill-in pickers
request an end-of-day boundary for Today.

Closes
https://linear.app/codercom/issue/CODAGT-751/date-range-picker-uses-end-of-hour-for-today

Generated by Coder Agents.
This commit is contained in:
Michael Suchacz
2026-07-07 11:20:16 +02:00
committed by GitHub
parent 8996506d43
commit 07f4c9f550
3 changed files with 46 additions and 3 deletions
@@ -21,6 +21,7 @@ import { useAuthenticated } from "#/hooks/useAuthenticated";
import { usePaginatedQuery } from "#/hooks/usePaginatedQuery";
import { RequirePermission } from "#/modules/permissions/RequirePermission";
import { SpendPageView } from "./SpendPageView";
import { toExclusiveEndOfDayDateRange } from "./utils/dateRange";
const startDateSearchParam = "startDate";
const endDateSearchParam = "endDate";
@@ -132,11 +133,13 @@ const SpendPage: FC<SpendPageProps> = ({ now }) => {
};
const onDateRangeChange = (value: DateRangeValue) => {
const nextDateRange = toExclusiveEndOfDayDateRange(value);
setSearchParams(
(prev) => {
const next = new URLSearchParams(prev);
next.set(startDateSearchParam, value.startDate.toISOString());
next.set(endDateSearchParam, value.endDate.toISOString());
next.set(startDateSearchParam, nextDateRange.startDate.toISOString());
next.set(endDateSearchParam, nextDateRange.endDate.toISOString());
next.delete("page");
return next;
},
@@ -1,5 +1,32 @@
import { describe, expect, it } from "vitest";
import { formatUsageDateRange, toInclusiveDateRange } from "./dateRange";
import {
formatUsageDateRange,
toExclusiveEndOfDayDateRange,
toInclusiveDateRange,
} from "./dateRange";
describe("toExclusiveEndOfDayDateRange", () => {
it("moves a non-midnight end date to the next midnight", () => {
const startDate = new Date(2025, 5, 1, 0, 0, 0, 0);
const endDate = new Date(2025, 5, 8, 14, 30, 0, 0);
const result = toExclusiveEndOfDayDateRange({ startDate, endDate });
expect(result.endDate).toEqual(new Date(2025, 5, 9, 0, 0, 0, 0));
});
it("returns unchanged when the end date is already midnight", () => {
const startDate = new Date(2025, 5, 1, 0, 0, 0, 0);
const endDate = new Date(2025, 5, 8, 0, 0, 0, 0);
const result = toExclusiveEndOfDayDateRange({ startDate, endDate });
expect(result.endDate).toBe(endDate);
});
it("preserves startDate", () => {
const startDate = new Date(2025, 5, 1, 0, 0, 0, 0);
const endDate = new Date(2025, 5, 8, 14, 30, 0, 0);
const result = toExclusiveEndOfDayDateRange({ startDate, endDate });
expect(result.startDate).toBe(startDate);
});
});
describe("toInclusiveDateRange", () => {
it("subtracts 1ms when endDateIsExclusive is true and end date is midnight", () => {
@@ -16,6 +16,19 @@ function isMidnight(date: Date): boolean {
);
}
export function toExclusiveEndOfDayDateRange(
dateRange: DateRangeValue,
): DateRangeValue {
if (isMidnight(dateRange.endDate)) {
return dateRange;
}
return {
startDate: dateRange.startDate,
endDate: dayjs(dateRange.endDate).startOf("day").add(1, "day").toDate(),
};
}
/**
* When the user picks an explicit date range whose end boundary is
* midnight of the following day, adjust it by −1 ms so the