Live-service games love recurring events that start at a fixed UTC time. Players, though, live in every time zone, and "the event starts at 18:00 UTC" is a common source of confusion. Here is a small, dependency-free way to show event times in the visitor's own zone.

1. Store the schedule in UTC

// Daily event windows, defined once in UTC const EVENT_WINDOWS_UTC = [ { start: "14:00", durationMin: 60 }, { start: "20:00", durationMin: 60 }, ]; 

2. Build the next occurrence as a real Date

function nextOccurrence({ start, durationMin }, now = new Date()) { const [h, m] = start.split(":").map(Number); const d = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), h, m)); if (d.getTime() + durationMin * 60000 < now.getTime()) d.setUTCDate(d.getUTCDate() + 1); return d; } 

3. Format it with Intl, which knows the user's zone

const fmt = new Intl.DateTimeFormat(undefined, { weekday: "short", hour: "2-digit", minute: "2-digit", timeZoneName: "short", }); for (const w of EVENT_WINDOWS_UTC) { console.log(fmt.format(nextOccurrence(w))); } 

Intl.DateTimeFormat().resolvedOptions().timeZone returns the IANA zone (for example Asia/Shanghai), so you can also let users pick another zone and pass timeZone explicitly.

4. Add a countdown

function countdown(target) { const s = Math.max(0, Math.floor((target - Date.now()) / 1000)); const hh = String(Math.floor(s / 3600)).padStart(2, "0"); const mm = String(Math.floor((s % 3600) / 60)).padStart(2, "0"); return `${hh}:${mm}`; } 

Gotchas

  • Daylight saving time: keep the source of truth in UTC and convert at display time, never the other way round.
  • Don't parse "14:00" with new Date("14:00"); browsers disagree.
  • Cache nothing that depends on the user's zone on the server.

A real-world example

If you want to see this pattern in a finished page, FN Power Hour is a free fan-made planner that shows Fortnite Treasure Hours in your own time zone; it also has a chest tracker.

Happy building!