fix: show proper date and local kickoff time in Upcoming Fixtures
formatKickoff() converts "HH:MM UTC-4" + ISO date into the viewer's local timezone using Date.UTC arithmetic. Shows "Today", "Tomorrow", or "Mon 16 Jun" as the day label, appended with the local kickoff time. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+28
-2
@@ -53,8 +53,34 @@ interface UpcomingMatch {
|
|||||||
team2: { name: string; iso2?: string | null }
|
team2: { name: string; iso2?: string | null }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatKickoff(date: string | null | undefined, time: string | null | undefined): string {
|
||||||
|
if (!date) return ''
|
||||||
|
const today = new Date()
|
||||||
|
const tomorrow = new Date(today); tomorrow.setDate(today.getDate() + 1)
|
||||||
|
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'
|
||||||
|
: 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 }) {
|
function UpcomingFixture({ match }: { match: UpcomingMatch }) {
|
||||||
const time = match.time?.split(' ')[0] ?? ''
|
const label = formatKickoff(match.date, match.time)
|
||||||
return (
|
return (
|
||||||
<Link href={`/tournaments/${match.year}#match-${match.id}`}>
|
<Link href={`/tournaments/${match.year}#match-${match.id}`}>
|
||||||
<div className="glass-card rounded-[10px] p-3 px-4 flex items-center gap-2.5 hover:border-green/20 transition-colors cursor-pointer">
|
<div className="glass-card rounded-[10px] p-3 px-4 flex items-center gap-2.5 hover:border-green/20 transition-colors cursor-pointer">
|
||||||
@@ -63,7 +89,7 @@ function UpcomingFixture({ match }: { match: UpcomingMatch }) {
|
|||||||
{match.team1.name} <span className="text-green-muted">vs</span> {match.team2.name}
|
{match.team1.name} <span className="text-green-muted">vs</span> {match.team2.name}
|
||||||
</div>
|
</div>
|
||||||
<TeamFlag name={match.team2.name} iso2={match.team2.iso2} size="sm" />
|
<TeamFlag name={match.team2.name} iso2={match.team2.iso2} size="sm" />
|
||||||
{time && <div className="text-[11px] text-green-muted whitespace-nowrap ml-1">{time}</div>}
|
{label && <div className="text-[11px] text-green-muted whitespace-nowrap ml-1">{label}</div>}
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user