Skip to content

Time zones and DST in JavaScript: which date library handles them

  • The core functions, which every industry uses.

Temporal is built into Chrome 144, Firefox 139 and Node.js 26. Temporal.ZonedDateTime holds an IANA time zone and applies its DST rules, and it takes an explicit disambiguation for a wall-clock time that falls in a gap or an overlap. @northguild/gmt is built on Temporal. It takes and returns ISO 8601 and RFC 9557 strings, and adds functions for jobs Temporal leaves to you, such as business days, intervals and formatting.

The table below lists what each library needs for time zones and what it returns for a wall-clock time that does not exist.

The test input is 2024-03-31T02:30:00 in Europe/Berlin. The clocks skip from 02:00 to 03:00 that day, so 02:30 does not exist. Every result is shown as a UTC instant. Temporal’s compatible rule moves the time forward by the length of the gap (Temporal 11.1.12, DisambiguatePossibleEpochNanoseconds).

LibraryVersion testedTime zonesResult for the gapCase
Temporal (native)Node.js 26.12.1Built in2024-03-31T01:30:00ZM4
@northguild/gmt1.20.0Built in (uses Temporal)2024-03-31T01:30:00ZM4
Luxon3.7.2Built in, through Intl2024-03-31T01:30:00.000ZM4
date-fns4.4.0Add-on needed: @date-fns/tz 1.5.0 (or date-fns-tz)Depends on the host zoneM4
Day.js1.11.23Plugins needed: utc and timezone2024-03-31T01:30:00ZM4
Moment.js2.31.0Add-on needed: moment-timezone 0.6.52024-03-31T01:30:00ZM4
@internationalized/date3.12.4Built in (ZonedDateTime)2024-03-31T01:30:00.000ZM4

For date-fns with @date-fns/tz, the result depends on the zone of the machine that runs the code. On hosts set to Asia/Kolkata, Australia/Sydney or America/Santiago it is 2024-03-31T01:30:00.000+00:00. On a host set to Europe/London it is 2024-03-31T00:30:00.000+00:00. Temporal and GMT read no host zone and give the same result on every host.

Only Temporal, GMT and @internationalized/date can refuse the time. Date-fns, Luxon, Day.js and Moment.js always resolve it (M4b).

The results were measured on 2026-10-27 with the versions in the table. Behaviour of date libraries against Temporal lists every case, the call that produced each result and the clauses of the specification.

new Date("2024-03-31T02:30:00") has no zone in the string. It reads the string in the zone of the machine, so the same code returns different instants on different machines. resolveLocal takes the zone as an argument.

import { resolveLocal } from "@northguild/gmt/instant/convert";
resolveLocal("2024-03-31T02:30:00", "Europe/Berlin"); // "2024-03-31T01:30:00Z"
resolveLocal("2024-03-31T02:30:00", "Europe/Berlin", { disambiguation: "reject" }); // ""

The default is compatible, so the time moves forward to 03:30 Berlin time, which is 01:30 UTC. With reject, resolveLocal returns "" because the time does not exist, and your code can treat it as an error. The four values are compatible, earlier, later and reject (Temporal 13.7).

To find out which case you have before you choose an instant, call classifyLocal.

import { classifyLocal } from "@northguild/gmt/instant/convert";
classifyLocal("2024-03-31T02:30:00", "Europe/Berlin"); // "nonexistent"

Check whether a local time exists on a DST day covers gaps and overlaps in more zones.

One calendar day after 2024-03-30T02:30 in Berlin is 03:30 on 2024-03-31, because 02:30 does not exist that day (Temporal 6.5.5, AddZonedDateTime).

import { addZoned } from "@northguild/gmt/zoned/calculate";
addZoned("2024-03-30T02:30:00+01:00[Europe/Berlin]", { days: 1 }); // "2024-03-31T03:30:00+02:00[Europe/Berlin]"

Day.js with its timezone plugin returns 2024-03-31T02:30:00+01:00 for the same input, which is a time that does not exist on that day (M1).

Checked on 2026-10-27 with GMT 1.20.0. The runtime versions come from the MDN browser compatibility data as listed on Native Temporal and GMT. The time zone claims for each library come from its own documentation: Luxon, @date-fns/tz, Day.js timezone plugin, Moment Timezone and @internationalized/date.

See also: resolveLocal, classifyLocal, addZoned, and the guide DST Disambiguation.

Code examples: MIT-0. Packages: MIT. Third-party data and components: their own licences, credited where they appear. Everything else:© 2026 NorthGuild, all rights reserved.