Skip to content

GetOffsetNanosecondsFor validation may preclude some use cases #2725

@ptomato

Description

@ptomato

As discussed in the Temporal champions meeting of 2023-11-09.

We have restrictions on the values that may be returned from a custom time zone's getOffsetNanosecondsFor() method, defined in the GetOffsetNanosecondsFor AO: the return value must be an integral Number, with an absolute value less than 86400×10⁻⁹ (the number of nanoseconds in 24 hours).

This last restriction has been present for many years, since before we introduced custom time zones. There are two reasons why such a restriction on UTC offsets isn't a problem for built-in time zones:

  1. There aren't any existing time zones with a UTC offset that even comes close to that limit. The largest UTC offset "in the wild" is 14 hours. A UTC offset of ≥ 24 hours means going around the international date line at least once, so it would be equivalent to a shorter UTC offset but on a different day.
  2. It's not clear whether it's possible to serialize such a long UTC offset in an ISO 8601 string. ISO 8601 itself doesn't say anything about a limit, but allows a 2-digit hour, so there is an effective limit of ±99:99. RFC 3339 limits the hour to 24, so there is a limit of ±24:59 (although that might have been intended to mean ±24:00 as with the time component.) It seems plausible that string processors in the wild might choke on UTC offsets longer than 24 hours. (Including new Date() in JS, which returns an invalid Date object for any UTC offset ±24:00 or larger.)

When we added custom time zones in stage 2, we kept the same restriction. However, the "New York Stock Exchange time zone" cookbook example, as currently implemented, requires having UTC offsets of more than 24 hours. In this use case, if you have an exact time on Friday night, the UTC offset will be such that the clock time is Monday morning, more than 24 hours. This cookbook example has been broken since it was introduced, but we never noticed this because by coincidence the example code only used exact times where the limit wasn't exceeded.

You can easily get the stock exchange code to throw an exception:

zdt = Temporal.ZonedDateTime.from('2023-11-10T21:00[America/New_York]').withTimeZone(tzNYSE);
zdt.toPlainDateTime();  // throws, getOffsetNanosecondsFor would return 55:30

We need to determine whether this use case is compelling enough to make changes. It's a pretty obscure use case and not what people usually understand as a "time zone".

Here are the potential solutions we discussed:

  1. Do nothing. Use cases such as NYSE time zone would have to override other TimeZone.prototype methods such as getPlainDateTimeFor, and getInstantFor, and use those methods directly. Document that if you need excessively long UTC offsets, most built-in operations won't work.
  2. Relax the restriction.
  3. Change Temporal to call TimeZone.prototype.getPlainDateTimeFor internally instead of getOffsetNanosecondsFor, so that use cases such as NYSE time zone can override those methods and have them just work.
    3a) Alternatively, change Temporal to call getPlainDateTimeFor only if it exists, so that you can still create a custom time zone by just overriding getOffsetNanosecondsFor and getPossibleInstantsFor.

In the meeting, we didn't have much appetite for (3) or (3a). We noted that it is weird if your custom time zone implements both getOffsetNanosecondsFor and getPlainDateTimeFor, and you have a bug in one of them, then they can disagree. However, this would also be the case if getPlainDateTimeFor were the fundamental operation instead of vice versa.

To do (2), we'd have to decide on a limit (99 hours? 1 week? 104 days?) We'd also have to determine whether anything else in Temporal relies on the assumption that UTC offsets are less than 24 hours.

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationAdditions to documentation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions