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");
}
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
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
- 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.
-
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. -
Countdowns drift. Compute
target - Date.now()on every tick instead of decrementing a counter; background tabs throttle timers. -
Temporal is coming. Once
Temporalships everywhere,Temporal.ZonedDateTime.from({ timeZone, year, month, day })replaces the whole helper. Until then, theIntlapproach 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)