Skip to content

maxPossibleTransition initialized from new Date() at module scope breaks timezone offsets in Cloudflare Workers #83

@apcoates

Description

@apcoates

I encountered a vexing issue in my Cloudflare deployment that uses temporal-polyfill in Workers environment. DST offsets are evidently computed incorrectly for any dates after 1980.

  // April 15, 2026 should be PDT (UTC-7), not PST (UTC-8)
  const april = Temporal.PlainDateTime.from('2026-04-15T09:00:00');
  const aprilZoned = april.toZonedDateTime('America/Los_Angeles'); // has -8h offset instead of -7

  // January 20, 2026 should be PST (UTC-8) - this works correctly
  const january = Temporal.PlainDateTime.from('2026-01-20T09:00:00');
  const januaryZoned = january.toZonedDateTime('America/Los_Angeles');
  • aprilZoned.toString() incorrectly produces: "2026-04-15T09:00:00-08:00[America/Los_Angeles]"
  • januaryZoned.toString() correctly produces: "2026-01-20T09:00:00-08:00[America/Los_Angeles]"

This is apparently caused by maxPossibleTransition being initialized via getCurrentYearPlus10() at module scope. Cloudflare's Date returns 0 in this case and thus all dates after 1980 run into the clamping logic elsewhere (see https://community.cloudflare.com/t/date-in-worker-is-reporting-thu-jan-01-1970-0000-gmt-0000/236503 )

I put up a clean reproducer here if useful: https://github.com/apcoates/temporal-polyfill-cloudflare-offset-bug

While not strictly a bug in temporal-polyfill itself, this could potentially be fixed with a one-line patch that strictly improves things (and saves others some headaches):

  function getCurrentYearPlus10() {
     const currentDate = /*@__PURE__*/ new Date()
     const currentYear = /*@__PURE__*/ currentDate.getUTCFullYear()
  -  return currentYear + 10
  +  return currentDate.getTime() === 0 ? 2050 : currentYear + 10
   }

One could also try to lazily initialize the maxPossibleTransition value, etc. to avoid the issue.

I've worked around by patching locally, but an upstream fix would be awesome.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions