iamkun / dayjs

⏰ Day.js 2kB immutable date-time library alternative to Moment.js with the same modern API
https://day.js.org
MIT License
46.78k stars 2.29k forks source link

Set hour not working with UTC timezone #2676

Open sciffany opened 3 months ago

sciffany commented 3 months ago

Describe the bug Set hour does not work properly when timezone is UTC or any other timezone with UTC offset 0.

dayjs('2024-06-16T00:00:00.000Z').tz('UTC').set('hour', 13).toDate().toISOString()

Expected behavior Expected Return: 2024-06-16T13:00:00:00.000Z Actual Return 2024-06-15T21:00:00:00.000Z

Information

tuanbht commented 3 months ago

+1

SaichandChowdary commented 3 months ago

@sciffany @tuanbht

I think the flow is as follows:

  1. dayjs('2024-06-16T00:00:00.000Z') ==> timestamp in local timezone ==> 2024-06-16T00:00:00+08:00 (GMT+8)
  2. .tz('UTC') ==> converted to UTC timezone ==> 2024-06-15T16:00:00+00:00 (GMT)
  3. .set('hour', 13) ==> hour set to 13 ==> 2024-06-15T13:00:00+00:00 (GMT)
  4. .toDate() ==> converted to date object
  5. .toISOString() ==> to string in local timezone ==> 2024-06-15T21:00:00+08:00 (GMT+8)

In order to print the time in UTC, you may try the following, that should return the expected output. dayjs('2024-06-16T00:00:00.000Z').tz('UTC').set('hour', 13).format('YYYY-MM-DDTHH:mm:ssZ[Z]')

sciffany commented 3 months ago

@SaichandChowdary Thanks for looking into the issue!

I understand the flow you mentioned. Step 1 is a little strange because Z normally already means UTC time, so why interpret it as GMT+8. Step 5 is odd because toISOString is supposed to return GMT time as well, not GMT+8 time.

For the last line you mentioned, 2024-06-15T13:00:00+00:00Z This is the return value. It's still not 2024-06-16T13:00:00+00:00Z

SaichandChowdary commented 3 months ago

@sciffany Thanks for your answers.

I leave it to the contributors to further investigate this issue (as to why Z isn't considered in step 1 and toISOString is not returning in GMT timezone in step 5)

emojiiii commented 3 months ago

If you want to parse or display in UTC, you can use dayjs.utc() instead of dayjs()

dayjs.utc('2024-06-16T00:00:00.000Z').tz('UTC').set('hour', 13).toDate().toISOString()
sciffany commented 3 months ago

Yes, we have used this workaround in our code