date-fns-tz icon indicating copy to clipboard operation
date-fns-tz copied to clipboard

getTimezoneOffset off with one hour?

Open turboteddy opened this issue 2 years ago • 8 comments

I've debugged my code for a long time, because my a particular test fails over and over again. The test case resolves around figuring out whether there is a switch in "DST mode" (winter to summer time, or vice versa) for a given time range (2 date objects) and a given time zone (which neither is UTC or client time zone). Here is the case:

For Europe/Oslo, the following is true (winter to summer time): Sunday, 27 March 2022, 02:00:00 clocks are turned forward 1 hour to.... Sunday, 27 March 2022, 03:00:00 local daylight time instead.

This can easily be checked with vanilla getTimezoneOffset (I'm using latest version of Chrome), when client is set to the Europe/Oslo time zone:

d1 = new Date("2022-03-27T00:30:00.000Z"); 
// Sun Mar 27 2022 01:30:00 GMT+0100 (Central European Standard Time)

d2 = new Date("2022-03-27T01:30:00.000Z"); 
// Sun Mar 27 2022 03:30:00 GMT+0200 (Central European Summer Time)

d1.getTimezoneOffset();
// -60
d2.getTimezoneOffset()
//-120

Correspondingly, one should get the same result when using date-fns-tz getTimezoneOffset - but the result differs...

import { getTimezoneOffset } from "date-fns-tz";

d1 = new Date("2022-03-27T00:30:00.000Z"); 
// Sun Mar 27 2022 01:30:00 GMT+0100 (Central European Standard Time)

d2 = new Date("2022-03-27T01:30:00.000Z"); 
// Sun Mar 27 2022 03:30:00 GMT+0200 (Central European Summer Time)

getTimezoneOffset("Europe/Oslo", d1) / (-1 * 60 * 1000);
// -60

getTimezoneOffset("Europe/Oslo", d2) / (-1 * 60 * 1000);
// -60 <--- WRONG?!

However, if I try with one hour later, date-fns-tz getTimezoneOffset seems to get it right again...

import { getTimezoneOffset } from "date-fns-tz";

d3 = new Date("2022-03-27T02:30:00.000Z"); 
// Sun Mar 27 2022 04:30:00 GMT+0200 (Central European Summer Time)

getTimezoneOffset("Europe/Oslo", d3) / (-1 * 60 * 1000);
// -120

Could it be that date-fns-tz getTimezoneOffset is off with one hour?

turboteddy avatar May 08 '22 12:05 turboteddy

FYI: Tested with both version 1.2.2 and 1.3.4 of date-fns-tz (seems to be the same problem)

turboteddy avatar May 08 '22 13:05 turboteddy

Unfortunately, I'm also facing similar issue getTimezoneOffset is not acting how it suppose to. It would be great someone you give a proper fix for this issue otherwise, I have to write some extra unnecessary code for overcoming this.

raihan-brain avatar May 10 '22 12:05 raihan-brain

I might be wrong but it looks like(from the code and existing spec) that date is treated as date in the time zone (offset is ignored). With that logic applied - results that you get are expected.

healqq avatar May 14 '22 17:05 healqq

@healqq : I'm not sure if I understand what you mean:

I might be wrong but it looks like(from the code and existing spec) that date is treated as date in the time zone (offset is ignored). With that logic applied - results that you get are expected.

I'd expect getTimezoneOffset not to ignore offset - it's the very essence of the function. And it's working for most cases, just not for the cases described by this bug report.

turboteddy avatar May 27 '22 06:05 turboteddy

I'm having a similar issue, it seems to be specific for the DST boundaries, so for 2023 DST starts on March 23 02:00 EST, I have a simple test code for it

  const { format, utcToZonedTime, getTimezoneOffset, zonedTimeToUtc } = require('date-fns-tz');
  const timeZone = 'America/New_York';  
  
  const fn = (dateStr) => {
    const dateFns = zonedTimeToUtc(dateStr, timeZone);
    console.log(dateFns.toISOString());
    console.log(getTimezoneOffset(timeZone, dateFns) / ((60000 * 60)));
  }
  
  fn('2023-03-12 01:00:00');
  /**
   * 2023-03-12T06:00:00.000Z
   * -4
   * Time is OK, but offset should be -5
   */
  fn('2023-03-12 02:00:00');
  /**
   * 2023-03-12T06:00:00.000Z
   * -4
   * Time is off since 02:00 am do not exists since is when DST starts, so it should be 03:00 (07:00 UTC)
   */
  fn('2023-03-12 03:00:00');
  /**
   * 2023-03-12T07:00:00.000Z
   * -4
   * 
   * This one is fine
   */

jscida avatar Jun 08 '22 18:06 jscida

This one just came up for us. We took a timeZone name to display the offset GMT-04:00 kind of thing and didn't notice it until we provided America/Santiago this week, before the timezone shift on 2020-09-11. So we're currently seeing GMT-03:00, but we should be seeing GMT-04:00 until Sunday.

We've just been passing in the current date (new Date()) as the formatted date using the following code: formatInTimeZone(new Date(), 'America/Santiago', 'OOOO'); which should spit it out correctly, but alas its an hour off.

Has anyone come up with a workaround or fix for this?

ericchernuka avatar Sep 10 '22 00:09 ericchernuka

Whilst I still struggle with TZ; I think the logic of the current tests are wrong: https://github.com/marnusw/date-fns-tz/blob/4ced7b8b0a5aad5b08fc3a44476242c82bc3272d/src/getTimezoneOffset/test.js#L53-L55 and https://github.com/marnusw/date-fns-tz/blob/4ced7b8b0a5aad5b08fc3a44476242c82bc3272d/src/getTimezoneOffset/test.js#L58-L60 Seems to be checking that 'Australia/Melbourne' enter DST at 02:00 UTC but they actually do it at 02:00 local time. I believe the correct tests should be var date = new Date('2020-10-04T01:45:00.000+10:00') and var date = new Date('2020-10-04T03:15:00.000+11:00'). This currently causes the tests to "fail" which I think implies the logic also needs changing?

BarnabyShearer avatar Oct 05 '22 18:10 BarnabyShearer

This is exactly the bug, getTimezoneOffset returns wrong value on DST change, for 1 hour. In below example you can see that momentjs or native js methods returns correct value for the same timestamp.

I've found this bug on highcharts chart using offset to correctly display datetime string on xAxis. Dates were displayed incorrectly.

Stackblitz example demo

Random90 avatar Nov 04 '22 12:11 Random90