Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions src/server/features/gsc/searchAnalytics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,39 @@ import {

const TODAY = new Date("2026-05-28T00:00:00Z");

/** GSC counts startDate and endDate inclusively, so the window a range asks
* for must match the days GSC will actually bill it for. */
function inclusiveDays(startDate: string, endDate: string): number {
const dayMs = 24 * 60 * 60 * 1000;
const start = Date.parse(`${startDate}T00:00:00Z`);
const end = Date.parse(`${endDate}T00:00:00Z`);
return (end - start) / dayMs + 1;
}

describe("resolveDateRange", () => {
it("ends convenience ranges 3 days back for GSC data lag", () => {
const { endDate } = resolveDateRange({ dateRange: "last_28_days" }, TODAY);
expect(endDate).toBe("2026-05-25");
});

it("computes a 28-day window from the lagged end", () => {
it("spans 28 inclusive days from the lagged end", () => {
const { startDate, endDate } = resolveDateRange(
{ dateRange: "last_28_days" },
TODAY,
);
expect(startDate).toBe("2026-04-27");
expect(startDate).toBe("2026-04-28");
expect(endDate).toBe("2026-05-25");
expect(inclusiveDays(startDate, endDate)).toBe(28);
});

it("spans 7 inclusive days from the lagged end", () => {
const { startDate, endDate } = resolveDateRange(
{ dateRange: "last_7_days" },
TODAY,
);
expect(startDate).toBe("2026-05-19");
expect(endDate).toBe("2026-05-25");
expect(inclusiveDays(startDate, endDate)).toBe(7);
});

it("clamps the start to the 16-month floor", () => {
Expand Down Expand Up @@ -52,7 +72,9 @@ describe("resolveDateRange", () => {
{ dateRange: "last_3_months" },
new Date("2026-06-03T00:00:00Z"),
);
expect(startDate).toBe("2026-02-28");
// Feb 28 is the clamped subtraction; the window starts the day after it so
// Mar 1 - May 31 covers three whole months rather than three months plus a day.
expect(startDate).toBe("2026-03-01");
expect(endDate).toBe("2026-05-31");
});

Expand Down
20 changes: 14 additions & 6 deletions src/server/features/gsc/searchAnalytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,27 +85,35 @@ function subtractUtcMonths(date: Date, months: number): Date {
return d;
}

// GSC treats startDate and endDate as inclusive, so an N-day range starts
// N-1 days back and a calendar-month range starts the day after the subtraction.
function subtractRange(end: Date, range: GscDateRange): Date {
const d = new Date(end);
switch (range) {
case "last_7_days":
d.setUTCDate(d.getUTCDate() - 7);
d.setUTCDate(d.getUTCDate() - 6);
break;
case "last_28_days":
d.setUTCDate(d.getUTCDate() - 28);
d.setUTCDate(d.getUTCDate() - 27);
break;
case "last_3_months":
return subtractUtcMonths(d, 3);
return nextUtcDay(subtractUtcMonths(d, 3));
case "last_6_months":
return subtractUtcMonths(d, 6);
return nextUtcDay(subtractUtcMonths(d, 6));
case "last_12_months":
return subtractUtcMonths(d, 12);
return nextUtcDay(subtractUtcMonths(d, 12));
case "last_16_months":
return subtractUtcMonths(d, 16);
return nextUtcDay(subtractUtcMonths(d, 16));
}
return d;
}

function nextUtcDay(date: Date): Date {
const d = new Date(date);
d.setUTCDate(d.getUTCDate() + 1);
return d;
}

function sixteenMonthFloor(today: Date): string {
return formatDate(subtractUtcMonths(today, 16));
}
Expand Down