Open LeonanCarvalho opened 2 years ago
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!
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.
Indeed, it looks like the time changes every time a timezone conversion occurs:
I'm on Day.js 1.10.7 (and currently in Paris).
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.
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.
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
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.
I commented above here, and the behavior I described above is also fixed in 1.11.2.
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.
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
dayjs('2022-11-19 15:45:55 UTC').tz('America/Los_angeles')
This fixed it for me and Idk why. Something to look into.
On version 1.11.7, specifying timezone has no effect. I'm only getting the local time.
This is a sandbox that reproduces the timezone not affecting the date: https://codesandbox.io/s/dayjs-business-time-forked-b7opew
Recommend this over dayjs if you want to handle timezone: https://www.npmjs.com/package/date-fns-tz
@pencilcheck date-fns-tz is a really pain :/
dayjs().tz('Asia/Jakarta').format();
use format(), this is working for me
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 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 formatAsia/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.
It seems the original bug is fixed? Could this issue be closed?
I have a trouble here
When I has a date like YYYY-MM-DDTHH:mm:ss
, and I try to add tz using tz('tz string', true)
to keep local time, everything works fine except tz(+00:00, true)
. It will change the time by my timezone. Do somebody meet this?
Some time zones are not converted correctly, especially "+00:00":
dayjs().tz('Atlantic/Azores').format('Z') => '+00:00'
dayjs('2024-02-01T00:00:00+00:00').tz('Atlantic/Azores', true).format() => '2024-02-01T02:00:00-01:00'
dayjs('2024-02-01T00:00:00+00:00').tz('Atlantic/Azores').locale('en').format() => '2024-01-31T23:00:00-01:00'
dayjs('2024-02-01T00:00:00+00:00').utc().locale('en').format() => '2024-02-01T00:00:00+00:00'
Same problem with all +00:00
timezones. I try to avoid this with a hackfix but now it does not works 😢 :
const convertToDayjs = (date: string | undefined, time: string | undefined, timezone: string) => {
const hourMin = time?.split(':');
const hour = Number.parseInt(hourMin?.[0] || '0', 10);
const min = Number.parseInt(hourMin?.[1] || '0', 10);
// Attention, gros bug avec dayJS et les timezones qui sont en UTC+00
// Du coup on triche en mettant un UTC fantoche
// et en reconvertissant dans la timezone cible
const tzDate = dayjs(date).tz(timezone);
const tzStrDate = tzDate.format('YYYY-MM-DD');
const tempUTCDate = dayjs.utc(tzStrDate, 'YYYY-MM-DD');
const currentDate = tempUTCDate
.set('hour', Number.isNaN(hour) ? 0 : hour)
.set('minute', Number.isNaN(min) ? 0 : min)
.startOf('minute');
// on reconverti dans la timezone cible en forçant la timezone et non en convertissant
return currentDate.tz(timezone, true);
};
Edit: My function works fine. The problem is dayJS with format
and toISOString
methods:
format
works fine and return correct dateTimetoISOString
return date after apply current navigator timezone before convert to UTC
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.2022-03-11T14:29:26.319Z
Fri, 11 Mar 2022 14:29:26 GMT
3/11/2022, 2:29:26 PM
2014-02-03T16:50:21Z
2012-02-01T13:50:21.01-03:00
2022-02-03T13:50:21-00: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