DEV Community

Emelie Fox
Emelie Fox

Posted on

How to Compute Rolling Midnight Game Unlock Times in JavaScript (GTA 6 Example)

Big game launches rarely unlock at one worldwide moment anymore. Grand Theft Auto VI is a good example: Rockstar has confirmed a November 19, 2026 launch with a midnight local-time unlock, and the PlayStation Store listings show a "rolling midnight" that starts in New Zealand and ends in Mexico roughly 19 hours later.

If you build a countdown widget, a Discord bot reminder, or a release-time table, you need to answer one question per region: what UTC instant is local midnight on launch day? Here is a small, dependency-free way to do it in JavaScript.

The naive approach (and why it breaks)

new Date("2026-11-19T00:00:00") gives you midnight in the machine's time zone, not the store's. Hard-coding offsets ("Spain is UTC+1") works until a daylight-saving change sneaks in between today and launch day. Let the IANA time-zone database do the work instead.

Local midnight to UTC with Intl only

The trick: start with midnight UTC, ask Intl.DateTimeFormat what wall-clock time that instant is in the target zone, compute the offset, and correct. Two passes handle DST edges.

// Find the UTC instant of local midnight on a date in an IANA time zone.
function localMidnightUTC(dateStr, timeZone) {
  const [y, m, d] = dateStr.split("-").map(Number);
  // Start from midnight UTC, then correct by the zone's offset at that moment.
  let guess = Date.UTC(y, m - 1, d, 0, 0, 0);
  for (let i = 0; i < 2; i++) {
    const parts = new Intl.DateTimeFormat("en-US", {
      timeZone, hourCycle: "h23",
      year: "numeric", month: "2-digit", day: "2-digit",
      hour: "2-digit", minute: "2-digit", second: "2-digit",
    }).formatToParts(new Date(guess));
    const get = (t) => Number(parts.find((p) => p.type === t).value);
    const asIfUTC = Date.UTC(get("year"), get("month") - 1, get("day"),
                             get("hour"), get("minute"), get("second"));
    const offset = asIfUTC - guess;          // zone offset in ms
    guess = Date.UTC(y, m - 1, d) - offset;  // local midnight in UTC
  }
  return new Date(guess);
}

const stores = {
  "New Zealand": "Pacific/Auckland",
  "Japan": "Asia/Tokyo",
  "Spain": "Europe/Madrid",
  "United Kingdom": "Europe/London",
  "Brazil": "America/Sao_Paulo",
  "United States (ET)": "America/New_York",
  "Mexico": "America/Mexico_City",
};

const rows = Object.entries(stores)
  .map(([name, tz]) => [name, localMidnightUTC("2026-11-19", tz)])
  .sort((a, b) => a[1] - b[1]);

for (const [name, when] of rows) {
  console.log(name.padEnd(20), when.toISOString().slice(0, 16).replace("T", " "), "UTC");
}
Enter fullscreen mode Exit fullscreen mode

Output:

New Zealand          2026-11-18 11:00 UTC
Japan                2026-11-18 15:00 UTC
Spain                2026-11-18 23:00 UTC
United Kingdom       2026-11-19 00:00 UTC
Brazil               2026-11-19 03:00 UTC
United States (ET)   2026-11-19 05:00 UTC
Mexico               2026-11-19 06:00 UTC
Enter fullscreen mode Exit fullscreen mode

Those values line up with the timestamps on the regional PlayStation Store listings, which is a nice sanity check that the zone math is right.

Things that bite in real projects

  1. One store, many zones. The U.S. store unlocks at midnight Eastern, so a player in Los Angeles gets the game at 9:00 p.m. on November 18. Map store regions to zones, not users' zones, then display the result in the user's zone.
  2. Show both clocks. Render the unlock in the viewer's local time with toLocaleString(undefined, { timeZoneName: "short" }) and keep the store-local label next to it. People trust the number more when they can see where it came from.
  3. Countdowns drift. Compute target - Date.now() on every tick instead of decrementing a counter; background tabs throttle timers.
  4. Temporal is coming. Once Temporal ships everywhere, Temporal.ZonedDateTime.from({ timeZone, year, month, day }) replaces the whole helper. Until then, the Intl approach works in every modern browser and in Node.

Where the data comes from

The code is the easy part; the inputs are the hard part. Store timestamps can change close to launch, so treat any table as "checked on a date" and re-verify. I keep a per-country table with the date we last read each listing at GTA 6 release time by country, and a live GTA 6 countdown built on the same idea.

— Emelie Fox, editor at HUDWire, an independent gaming news site not affiliated with Rockstar Games or Take-Two Interactive.

Top comments (0)