From 015f6c2ef391b08637e6b98b4c26858dad8a2d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kr=C3=BCger?= Date: Mon, 15 Jun 2026 19:34:20 +0200 Subject: [PATCH] fix: derive upcoming fixture day label from computed local kickoff time Previously used the stored venue date for Today/Tomorrow logic, which gave wrong results when the UTC kickoff crossed midnight into the next local day (e.g. 18:00 UTC-7 = 01:00 UTC next day). Now computes UTC kickoff first, converts to the viewer's local time, and derives the day label from that local Date object. Co-Authored-By: Claude Sonnet 4.6 --- app/page.tsx | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/app/page.tsx b/app/page.tsx index 258c4f3..bfb23b2 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -57,26 +57,30 @@ function formatKickoff(date: string | null | undefined, time: string | null | un if (!date) return '' const today = new Date() const tomorrow = new Date(today); tomorrow.setDate(today.getDate() + 1) + + if (time) { + const m = time.match(/^(\d{2}):(\d{2})(?:\s+UTC([+-]\d+(?:\.\d+)?))?/) + if (m) { + const [y, mo, d] = date.split('-').map(Number) + const h = parseInt(m[1]), min = parseInt(m[2]) + const offsetH = m[3] ? parseFloat(m[3]) : 0 + // Compute UTC kickoff, then let the browser render in its local timezone + const local = new Date(Date.UTC(y, mo - 1, d, h - offsetH, min)) + const isToday = local.toDateString() === today.toDateString() + const isTomorrow = local.toDateString() === tomorrow.toDateString() + const dayLabel = isToday ? 'Today' : isTomorrow ? 'Tomorrow' + : local.toLocaleDateString('en-GB', { weekday: 'short', day: 'numeric', month: 'short' }) + const localTime = local.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' }) + return `${dayLabel} · ${localTime}` + } + } + + // No time — fall back to venue date label only const matchDate = new Date(date + 'T00:00:00') const isToday = matchDate.toDateString() === today.toDateString() const isTomorrow = matchDate.toDateString() === tomorrow.toDateString() - const dayLabel = isToday ? 'Today' : isTomorrow ? 'Tomorrow' + return isToday ? 'Today' : isTomorrow ? 'Tomorrow' : matchDate.toLocaleDateString('en-GB', { weekday: 'short', day: 'numeric', month: 'short' }) - - if (!time) return dayLabel - - // Parse "HH:MM UTC±N" and convert to viewer's local time - const m = time.match(/^(\d{2}):(\d{2})(?:\s+UTC([+-]\d+(?:\.\d+)?))?/) - if (!m) return dayLabel - const h = parseInt(m[1]), min = parseInt(m[2]) - const offsetH = m[3] ? parseFloat(m[3]) : 0 - const utcMs = Date.UTC( - matchDate.getFullYear(), matchDate.getMonth(), matchDate.getDate(), - h - offsetH, min - ) - const local = new Date(utcMs) - const localTime = local.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' }) - return `${dayLabel} · ${localTime}` } function UpcomingFixture({ match }: { match: UpcomingMatch }) {