Skip to content

ZonedDateTime until / since assertion failure for same-day times across Fall DST #3141

@phensley

Description

@phensley

I've reported an assertion failure of the ZonedDateTime until / since methods js-temporal/temporal-polyfill#347 which also fails in Firefox 141.0 with a slightly different error.

The two ZonedDateTime are valid but their times span the Fall DST boundary:

const zone = 'America/Vancouver';

// Sunday, November 2, 2025 8:01:00 AM UTC
// 2025-11-02 01:01:00-07:00 Local
const epoch1 = 1762070460000;

// Sunday, November 2, 2025 9:00:00 AM UTC
// 2025-11-02 01:00:00-08:00 Local
const epoch2 = 1762074000000;

const date1 = Temporal.Instant.fromEpochMilliseconds(epoch2).toZonedDateTimeISO(zone);
const date2 = Temporal.Instant.fromEpochMilliseconds(epoch1).toZonedDateTimeISO(zone);

// date2.until(date1) also fails
date1.until(date2, { largestUnit: 'year', smallestUnit: 'millisecond' });

The polyfill throws:

RangeError: mixed-sign values not allowed as duration fields

 ❯ ES.RejectDuration ../../node_modules/.pnpm/@[email protected]/node_modules/@js-temporal/polyfill/lib/ecmascript.ts:3250:50
 ❯ new Duration ../../node_modules/.pnpm/@[email protected]/node_modules/@js-temporal/polyfill/lib/duration.ts:54:5
 ❯ TemporalDurationFromInternal ../../node_modules/.pnpm/@[email protected]/node_modules/@js-temporal/polyfill/lib/ecmascript.ts:3400:10
 ❯ ES.DifferenceTemporalZonedDateTime ../../node_modules/.pnpm/@[email protected]/node_modules/@js-temporal/polyfill/lib/ecmascript.ts:4383:14
 ❯ Temporal.ZonedDateTime.until ../../node_modules/.pnpm/@[email protected]/node_modules/@js-temporal/polyfill/lib/zoneddatetime.ts:226:12

Firefox throws:

Uncaught RangeError: duration value "hours" has a mismatched sign: -24

Given that both the polyfill and Firefox native implementations fail this may be the correct behavior for these inputs?

A valid result for these inputs could be "-1 minute" if using wall clock time / disambiguation, or "59 minutes"if using absolute time.

If the spec is correct and callers are expected to try-catch this call, perhaps a more clarifying error could be thrown by the controlling function (DifferenceZonedDateTime).

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions