formkit / tempo

📆 Parse, format, manipulate, and internationalize dates and times in JavaScript and TypeScript.
https://tempo.formkit.com
MIT License
2.34k stars 30 forks source link

Incorrect formatting between local DST boundaries #30

Closed andrew0 closed 6 months ago

andrew0 commented 7 months ago

The formatting function in this library works by applying an offset between the target and local timezones to the input Date object, then formatting that adjusted date object, which is technically representing a different moment in time. This causes problems when the resulting time lands in between a daylight saving time boundary, since there can be moments of time that are impossible to represent in certain timezones. For example, in American timezones, the time "March 10, 2024 at 2:30 AM" is impossible to represent, since the clocks jump from 1:59 AM to 3:00 AM. So the approach used by this library outputs an incorrect time around this boundary:

With this test script:

import { format } from '@formkit/tempo';

const date = new Date(Date.UTC(2024, 2, 10, 2, 30));

console.log(
  '@formkit/tempo:',
  format({
    date,
    format: { date: 'full', time: 'full' },
    tz: 'UTC',
  }),
);

console.log(
  'Intl.DateTimeFormat:',
  new Intl.DateTimeFormat('en-US', {
    dateStyle: 'full',
    timeStyle: 'full',
    timeZone: 'UTC',
  }).format(date),
);

The output with TZ=UTC is correct:

@formkit/tempo: Sunday, March 10, 2024 at 2:30:00 AM +0000
Intl.DateTimeFormat: Sunday, March 10, 2024 at 2:30:00 AM Coordinated Universal Time

But the output with TZ=America/New_York is incorrect:

@formkit/tempo: Sunday, March 10, 2024 at 3:30:00 AM +0000
Intl.DateTimeFormat: Sunday, March 10, 2024 at 2:30:00 AM Coordinated Universal Time