Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dayjs.tz() is building dates with incorrect timezone for many cases #1827

Open
LeonanCarvalho opened this issue Mar 11, 2022 · 19 comments
Open

Comments

@LeonanCarvalho
Copy link

LeonanCarvalho commented Mar 11, 2022

Describe the bug
When you try to use dayjs.tz factory it isn't providing the instance properly, even using some ISO formats and Date object string outputs.

Some examples using a UTC environment :

Input Output Expected
2022-03-11T14:29:26.319Z 2022-03-11T14:29:26-03:00 2022-03-11T11:29:26-03:00
Fri, 11 Mar 2022 14:29:26 GMT 2022-03-11T14:29:26-03:00 2022-03-11T11:29:26-03:00
3/11/2022, 2:29:26 PM 2022-03-11T14:29:26-03:00 2022-03-11T11:29:26-03:00
2014-02-03T16:50:21Z 2014-02-03T16:50:21-03:00 2014-02-03T13:50:21-03:00
2012-02-01T13:50:21.01-03:00 2012-02-01T16:50:21-03:00 2012-02-01T13:50:21-03:00
2022-02-03T13:50:21-00:00 2022-02-03T13:50:21-03:00 2022-02-03T10:50:21-03:00

The behavior is odd, for the Date input it fails sometimes but also should be accepted especially the ISO format native Date outputs.

Reproducible code:

https://gist.github.com/LeonanCarvalho/35d1596dcfb701255d04b93d70df69a0

Expected behavior
Construct dayjs with correct timezone.

Information

  • Day.js Version v1.10.8
  • OS: [e.g. iOS]
  • Browser: nodeJS v14.17.3
  • Time zone: UTC (tests in UTC but also in GMT -3)
@hbj
Copy link

hbj commented Mar 28, 2022

I was about to file a bug regarding dayjs.tz and found this one which seems related. The issue is that the function is not converting correctly between timezones. Simplest case to see is when converting to the same timezone is leading to the time to be changed!

Example:

dayjs.tz('2022-02-21 22:00', 'YYYY-MM-DD HH:mm', 'Europe/Paris').toISOString()
=> '2022-02-21T21:00:00.000Z'
dayjs.tz('2022-02-21 22:00', 'YYYY-MM-DD HH:mm', 'Europe/Paris').tz('Europe/Paris').toISOString()
=> '2022-02-21T22:00:00.000Z'

It seems to be applying the offset of the target timezone without taking into consideration the timezone of the original date!

@h-h-h-h
Copy link

h-h-h-h commented Mar 30, 2022

Let me contribute my tests:

console.log(
  [
    // ✔️ "2022-10-30T02:00:00+02:00"
    dayjs.utc("2022-10-30 00:00").tz("Europe/Berlin"),

    // ❌ "2022-10-30T02:00:00Z"
    // ➡️ "2022-10-30T02:00:00+01:00" would be correct (duplicate local hour because of DST).
    dayjs.utc("2022-10-30 01:00").tz("Europe/Berlin"),
    dayjs.utc("2022-10-30 00:00").add(1, "h").tz("Europe/Berlin"),

    // ✔️ "2022-10-30T03:00:00+01:00"
    dayjs.utc("2022-10-30 02:00").tz("Europe/Berlin"),
    dayjs.utc("2022-10-30 00:00").add(2, "h").tz("Europe/Berlin"),

    // With add()/subtract() on IANA object, you never get out of the wrong timezone.
    // ❌ "2022-11-03T05:00:00+02:00" (add())
    // ❌ "2022-10-26T04:00:00+01:00" (subtract())
    dayjs.utc("2022-10-30 00:00").tz("Europe/Berlin").add(100, "h"),
    dayjs.utc("2022-10-30 06:00").tz("Europe/Berlin").subtract(100, "h"),

    // BTW: When add(), subtract() etc. are patched, this should return "2022-03-27T03:00:00+02:00" (missing local hour because of DST).
    dayjs.tz("2022-03-27 01:00", "Europe/Berlin").add(1, "h"),
  ].map((d) => d.format())
);

This also touches #1816.

@ilyakamens
Copy link

ilyakamens commented Apr 21, 2022

Indeed, it looks like the time changes every time a timezone conversion occurs:

image

I'm on Day.js 1.10.7 (and currently in Paris).

@sevrai
Copy link

sevrai commented Apr 26, 2022

It seems to be related to the extra offset created by Summer Time.

The switch to summer time occurred March 27th at 2AM in Paris and I got these results on an instance based in Paris:

console.log(dayjs("2022-03-27T20:00:00.000Z").tz("Europe/Paris").toISOString())
> 2022-03-27T20:00:00.000Z
console.log(dayjs("2022-03-25T20:00:00.000Z").tz("Europe/Paris").toISOString())
> 2022-03-25T21:00:00.000Z

It looks like the lib is using the current offset of the instance timezone (UTC+2 at the execution time) instead of the real one at this date.

@LeonanCarvalho LeonanCarvalho changed the title dayjs.tz() is not building dates with correct timezone in many cases dayjs.tz() is not building dates with correct timezone for many cases May 2, 2022
@rush86999
Copy link

rush86999 commented Jun 6, 2022

I am adding my bug here as well instead of creating a new one.

Same nodejs environment: nodejs14.x
AWS lambda environment - serverless framework
"dayjs": "^1.11.0",

use the same exact date and calling timezone with true as second parameter adjusts the time to utc offset
example:

dayjs.tz.setDefault('America/Toronto')

const date = dayjs('2022-06-12T17:00:00-04:00').tz('America/Toronto', true).format()

console.log(date, ' date')
// date = 2022-06-12T17:00:00-04:00
const date2 = dayjs(date).tz('America/Toronto', true).format()

console.log(date2, ' date2')
// date2 = 2022-06-12T21:00:00-04:00

As you can see utc offset is applied if timezone is called twice. This is a bug and likely related to new nodejs environemnt possibly?

not sure at this point.

@den-by
Copy link

den-by commented Aug 12, 2022

dayjs.tz('2022-02-21 22:00', 'YYYY-MM-DD HH:mm', 'Europe/Paris').toISOString()
=> '2022-02-21T21:00:00.000Z'
dayjs.tz('2022-02-21 22:00', 'YYYY-MM-DD HH:mm', 'Europe/Paris').tz('Europe/Paris').toISOString()
=> '2022-02-21T22:00:00.000Z'

To date, I get the same result 2022-02-21T21:00:00.000Z in both cases
dayjs: 1.11.5
macOS
NodeJS: 16.13.1

@sevrai
Copy link

sevrai commented Aug 22, 2022

To date, I get the same result 2022-02-21T21:00:00.000Z in both cases dayjs: 1.11.5 macOS NodeJS: 16.13.1

I've got the same.

In my case, release 1.11.2 solved my problem.

@ilyakamens
Copy link

I commented above here, and the behavior I described above is also fixed in 1.11.2.

@hbj
Copy link

hbj commented Aug 25, 2022

My case seems also to be fixed. I tested it on the Day.js website in the console, so I don't know exactly in which version this has been fixed.

@tonyneel
Copy link

dayjs(2022-11-19).tz('America/Los_angeles') => "2022-11-18T16:00:00.000Z"

On my local it is correct. What can I do? Do I just need to use moment? I love this library but I am not sure if there is a workaround or not for timezones not working. I have had other issues with timezone as well but found workarounds.

dayjs: 1.11.5
Supabase server not suer what OS
NodeJS: 16.13.1

@tonyneel
Copy link

dayjs('2022-11-19 15:45:55 UTC').tz('America/Los_angeles')

This fixed it for me and Idk why. Something to look into.

@dcdavidheisnam
Copy link

On version 1.11.7, specifying timezone has no effect. I'm only getting the local time.

@ItayTur
Copy link

ItayTur commented Mar 16, 2023

This is a sandbox that reproduces the timezone not affecting the date:
https://codesandbox.io/s/dayjs-business-time-forked-b7opew

@pencilcheck
Copy link

@pencilcheck
Copy link

Recommend this over dayjs if you want to handle timezone: https://www.npmjs.com/package/date-fns-tz

@throrin19
Copy link

@pencilcheck date-fns-tz is a really pain :/

@anospoldigot
Copy link

dayjs().tz('Asia/Jakarta').format();

use format(), this is working for me

@LeonanCarvalho LeonanCarvalho changed the title dayjs.tz() is not building dates with correct timezone for many cases dayjs.tz() is building dates with incorrect timezone for many cases Jan 16, 2024
@Joeljt
Copy link

Joeljt commented Jan 18, 2024

It seems that dayjs can not handle the timezone with the format of Etc/GMT+8, you can get a barely correct result using this timezone format, but a correct result using the format Asia/Shanghai.

Here is my test case:

const originalDate = dayjs('2024-01-18T12:34:56');

// GMT-8 is actually GMT+8, 2024-01-18 12:34:56
console.log(originalDate.utc().tz('Etc/GMT-8').format('YYYY-MM-DD HH:mm:ss'));

// UTC standard time, correct
console.log(originalDate.utc().tz('Etc/GMT+0').format('YYYY-MM-DD HH:mm:ss')); 

// 2024-01-17 20:34:56, I have no idea what is going on here
console.log(originalDate.utc().tz('Etc/GMT+8').format('YYYY-MM-DD HH:mm:ss'));

@Joeljt
Copy link

Joeljt commented Jan 18, 2024

It seems that dayjs can not handle the timezone with the format of Etc/GMT+8, you can get a barely correct result using this timezone format, but a correct result using the format Asia/Shanghai.

Here is my test case:

const originalDate = dayjs('2024-01-18T12:34:56');

// GMT-8 is actually GMT+8, 2024-01-18 12:34:56
console.log(originalDate.utc().tz('Etc/GMT-8').format('YYYY-MM-DD HH:mm:ss'));

// UTC standard time, correct
console.log(originalDate.utc().tz('Etc/GMT+0').format('YYYY-MM-DD HH:mm:ss')); 

// 2024-01-17 20:34:56, I have no idea what is going on here
console.log(originalDate.utc().tz('Etc/GMT+8').format('YYYY-MM-DD HH:mm:ss'));

It turns out that the Etc/ prefix would make the meaning of the whole timezone to be completely opposite than the original meaning.

For example, the Etc/GMT-8 is identical to GMT+8, and Etc/GMT+2 is the same as GMT-2 alone.

So the problem is not with dayjs, but my misunderstanding of the IANA timezone standard, although it's a little counter intuitive.

Leaving a message here in case of people may run into the same problem like me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests