From 793e97dbbbe421b26d2e813644eaf735db73b192 Mon Sep 17 00:00:00 2001 From: jtricerolph Date: Thu, 23 Jul 2026 09:48:46 +0000 Subject: [PATCH] Fix week date range off-by-one in BST timezone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit toISOString() returns UTC — in BST (UTC+1) dates computed from new Date() land one day early. Replace with local date components via fmt()/localStr(). Affects Weekly, Monthly, Rolling12Weeks, Rolling12Months. Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/pages/Monthly.tsx | 6 ++++-- frontend/src/pages/Rolling12Months.tsx | 4 +++- frontend/src/pages/Rolling12Weeks.tsx | 4 +++- frontend/src/pages/Weekly.tsx | 10 +++++++--- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/frontend/src/pages/Monthly.tsx b/frontend/src/pages/Monthly.tsx index 030aab8..51bdf69 100644 --- a/frontend/src/pages/Monthly.tsx +++ b/frontend/src/pages/Monthly.tsx @@ -6,7 +6,9 @@ import { import { getActuals, getScheduled, getNetSales, getBudgets, downloadExport } from '../api' import type { DeptActuals, WageBudget } from '../types' -function fmt(d: Date): string { return d.toISOString().slice(0, 10) } +function fmt(d: Date): string { + return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}` +} function addDays(d: Date, n: number): Date { const r = new Date(d); r.setDate(r.getDate() + n); return r } function daysInMonth(y: number, m: number): number { return new Date(y, m, 0).getDate() } function fmtMoney(n: number): string { return `£${Math.round(n).toLocaleString('en-GB')}` } @@ -15,7 +17,7 @@ function pctClass(pct: number): string { return pct <= 100 ? 'pct-green' : pct < const DEPT_COLORS = ['#065f46','#059669','#0891b2','#7c3aed','#c2410c','#b45309','#0f766e','#4338ca','#be185d','#15803d'] export default function Monthly() { - const todayStr = new Date().toISOString().slice(0, 10) + const todayStr = fmt(new Date()) const todayYear = parseInt(todayStr.slice(0, 4)) const todayMonth = parseInt(todayStr.slice(5, 7)) diff --git a/frontend/src/pages/Rolling12Months.tsx b/frontend/src/pages/Rolling12Months.tsx index 7a4141e..a3bf2e4 100644 --- a/frontend/src/pages/Rolling12Months.tsx +++ b/frontend/src/pages/Rolling12Months.tsx @@ -6,7 +6,9 @@ import { import { getActuals, getNetSales, getBudgets, downloadExport } from '../api' import type { WageBudget } from '../types' -function fmt(d: Date): string { return d.toISOString().slice(0, 10) } +function fmt(d: Date): string { + return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}` +} function fmtMoney(n: number): string { return `£${Math.round(n).toLocaleString('en-GB')}` } function pctClass(p: number): string { return p <= 100 ? 'pct-green' : p <= 110 ? 'pct-amber' : 'pct-red' } function daysInMonth(y: number, m: number): number { return new Date(y, m, 0).getDate() } diff --git a/frontend/src/pages/Rolling12Weeks.tsx b/frontend/src/pages/Rolling12Weeks.tsx index eaf4b54..734d6eb 100644 --- a/frontend/src/pages/Rolling12Weeks.tsx +++ b/frontend/src/pages/Rolling12Weeks.tsx @@ -7,7 +7,9 @@ import { import { getActuals, getNetSales, getBudgets, downloadExport } from '../api' import type { WageBudget } from '../types' -function fmt(d: Date): string { return d.toISOString().slice(0, 10) } +function fmt(d: Date): string { + return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}` +} function addDays(d: Date, n: number): Date { const r = new Date(d); r.setDate(r.getDate() + n); return r } function startOfWeek(d: Date): Date { const day = d.getDay() diff --git a/frontend/src/pages/Weekly.tsx b/frontend/src/pages/Weekly.tsx index 3f56d4d..08a3cc2 100644 --- a/frontend/src/pages/Weekly.tsx +++ b/frontend/src/pages/Weekly.tsx @@ -3,18 +3,22 @@ import { ChevronLeft, ChevronRight, Download } from 'lucide-react' import { getActuals, getNetSales, getBudgets, downloadExport } from '../api' import type { DeptActuals, WageBudget } from '../types' +function localStr(d: Date): string { + return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}` +} + function mondayOf(d: Date): string { const day = d.getDay() const r = new Date(d) r.setDate(d.getDate() + (day === 0 ? -6 : 1 - day)) r.setHours(0, 0, 0, 0) - return r.toISOString().slice(0, 10) + return localStr(r) } function addDaysStr(dateStr: string, n: number): string { const d = new Date(dateStr + 'T00:00:00') d.setDate(d.getDate() + n) - return d.toISOString().slice(0, 10) + return localStr(d) } function daysInMonthFor(dateStr: string): number { @@ -41,7 +45,7 @@ export default function Weekly() { const [fromStr, setFromStr] = useState(() => mondayOf(new Date())) const toStr = addDaysStr(fromStr, 6) - const todayStr = new Date().toISOString().slice(0, 10) + const todayStr = localStr(new Date()) const [depts, setDepts] = useState([]) const [netSales, setNetSales] = useState(0)