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

Timezone conversion incorrect when daylight saving in effect #1260

Open
PaulJNewell77 opened this issue Dec 7, 2020 · 29 comments
Open

Timezone conversion incorrect when daylight saving in effect #1260

PaulJNewell77 opened this issue Dec 7, 2020 · 29 comments

Comments

@PaulJNewell77
Copy link

Describe the bug
Dayjs does not seem to convert timezone correctly when DST is in effect. It produces different results from Moment. The Moment results seem intuitively what I'd expect, so believe to be correct unless there is some subtlety I'm missing.

Expected behavior
With this code:

    const when = '2020-07-30T12:00:00+00:00'; // Midday GMT in summer
    console.log('Moment London: ' + moment(when).tz('Europe/London').format('HH:mm Z'));
    console.log('Moment New York: ' + moment(when).tz('America/New_York').format('HH:mm Z'));

    console.log('Dayjs London: ' + dayjs(when).tz('Europe/London').format('HH:mm Z'));
    console.log('Dayjs New York: ' + dayjs(when).tz('America/New_York').format('HH:mm Z'));

The output is:

    Moment London: 13:00 +01:00
    Moment New York: 08:00 -04:00
    Dayjs London: 12:00 +00:00 // Expect 13:00 +01:00
    Dayjs New York: 08:00 -05:00 // Expect 08:00 -04:00

Information

  • Day.js: v1.9.6
  • OS: Windows 10 Home
  • Nodejs: v12.8.3
  • Time zone: GMT+00:00
@alexanderankin
Copy link

is this whats going wrong in the test suite of this library? i ran it and some tests were off by an hour.

@PaulJNewell77
Copy link
Author

Hi, any thoughts on this issue @iamkun?

@lucasrcosta
Copy link

lucasrcosta commented Dec 31, 2020

I can confirm that tests are failing in a locale affected by daylight savings (I'm in America/Vancouver).

I found out because tests stared breaking locally, and I made some experiments showing output different from Moment: https://runkit.com/lucasrcosta/5feca83aea7c09001b879b3a

I tried sorting it out on the code and removing the current offset from localUtcOffset on timezone/index.js fixed one test, but I couldn't figure out solutions for the others. It does seem related to not fixing DST.

Summary of all failing tests

 FAIL  test/plugin/dayOfYear.test.js
  ● DayOfYear set

    expect(received).toBe(expected) // Object.is equality
    
    Expected value to be:
      "2015-01-04T00:00:00.000Z"
    Received:
      "2014-01-05T00:00:00.000Z"

      31 |   expect(dayjs('2015-01-01T00:00:00.000Z')
      32 |     .dayOfYear(4)
    > 33 |     .toISOString()).toBe('2015-01-04T00:00:00.000Z')
      34 | 
      35 |   expect(dayjs('2015-01-01T00:00:00.000Z')
      36 |     .dayOfYear(32)
      
      at Object.<anonymous> (test/plugin/dayOfYear.test.js:33:21)

 FAIL  test/plugin/localizedFormat.test.js
  ● Should not interpolate characters inside square brackets

    expect(received).toBe(expected) // Object.is equality
    
    Expected value to be:
      "1970 l 1970"
    Received:
      "1969 l 1969"

      29 | 
      30 |   expect(actualDate.format('[l]')).toBe('l')
    > 31 |   expect(actualDate.format('YYYY [l] YYYY')).toBe('1970 l 1970')
      32 |   expect(actualDate.format('l [l] l')).toBe('1/1/1970 l 1/1/1970')
      33 |   expect(actualDate.format('[L LL LLL LLLL]')).toBe(expectedDate.format('[L LL LLL LLLL]'))
      34 | 
      
      at Object.<anonymous> (test/plugin/localizedFormat.test.js:31:46)

 FAIL  test/plugin/timezone.test.js
  ● Parse › parse timestamp, js Date, Day.js object

    expect(received).toBe(expected) // Object.is equality
    
    Expected value to be:
      "2020-08-07T12:00:00-07:00"
    Received:
      "2020-08-07T12:00:00-08:00"

      49 |     const Timestamp = dayjs.tz(d.getTime(), VAN)
      50 |     const Tmoment = moment.tz(d, VAN)
    > 51 |     expect(TjsDate.format()).toBe(result)
      52 |     expect(Tdayjs.format()).toBe(result)
      53 |     expect(Timestamp.format()).toBe(result)
      54 |     expect(Tmoment.format()).toBe(result)
      
      at Object.<anonymous> (test/plugin/timezone.test.js:51:30)

  ● Parse › parse and convert between timezones

    expect(received).toBe(expected) // Object.is equality
    
    Expected value to be:
      "2014-06-01T09:00:00-07:00"
    Received:
      "2014-06-01T09:00:00-08:00"

      57 |   it('parse and convert between timezones', () => {
      58 |     const newYork = dayjs.tz('2014-06-01 12:00', NY)
    > 59 |     expect(newYork.tz('America/Los_Angeles').format()).toBe('2014-06-01T09:00:00-07:00')
      60 |     expect(newYork.tz('Europe/London').format()).toBe('2014-06-01T17:00:00+01:00')
      61 |   })
      62 | 
      
      at Object.<anonymous> (test/plugin/timezone.test.js:59:56)

  ● Convert › convert to target time

    expect(received).toBe(expected) // Object.is equality
    
    Expected value to be:
      "2014-06-01T05:00:00-07:00"
    Received:
      "2014-06-01T05:00:00-08:00"

      74 |     const losAngeles = dayjs('2014-06-01T12:00:00Z').tz('America/Los_Angeles')
      75 |     const MlosAngeles = moment('2014-06-01T12:00:00Z').tz('America/Los_Angeles')
    > 76 |     expect(losAngeles.format()).toBe('2014-06-01T05:00:00-07:00')
      77 |     expect(losAngeles.format()).toBe(MlosAngeles.format())
      78 |     expect(losAngeles.valueOf()).toBe(1401624000000)
      79 |     expect(losAngeles.valueOf()).toBe(MlosAngeles.valueOf())
      
      at Object.<anonymous> (test/plugin/timezone.test.js:76:33)

  ● Convert › convert to target time

    expect(received).toBe(expected) // Object.is equality
    
    Expected value to be:
      "2014-06-01T05:00:00-07:00"
    Received:
      "2014-06-01T05:00:00-08:00"

      85 |     [dayjs, moment].forEach((_) => {
      86 |       const losAngeles = _('2014-06-01T12:00:00Z').tz('America/Los_Angeles')
    > 87 |       expect(losAngeles.format()).toBe('2014-06-01T05:00:00-07:00')
      88 |       expect(losAngeles.valueOf()).toBe(1401624000000)
      89 |     })
      90 |   })
      
      at forEach (test/plugin/timezone.test.js:87:35)
          at Array.forEach (<anonymous>)
      at Object.<anonymous> (test/plugin/timezone.test.js:85:21)

  ● Convert › convert from time with timezone to target time

    expect(received).toBe(expected) // Object.is equality
    
    Expected value to be:
      "2014-06-01T12:00:00Z"
    Received:
      "2014-06-01T12:00:00-01:00"

      93 |     const losAngelesInUTC = dayjs('2014-06-01T05:00:00-07:00').tz('UTC')
      94 |     const MlosAngelesInUTC = moment('2014-06-01T05:00:00-07:00').tz('UTC')
    > 95 |     expect(losAngelesInUTC.format()).toBe('2014-06-01T12:00:00Z')
      96 |     expect(losAngelesInUTC.format()).toBe(MlosAngelesInUTC.format())
      97 |   })
      98 | 
      
      at Object.<anonymous> (test/plugin/timezone.test.js:95:38)

  ● Convert › format Z

    expect(received).toBe(expected) // Object.is equality
    
    Expected value to be:
      "+09:00"
    Received:
      "+08:00"

      115 |     [dayjs, moment].forEach((_) => {
      116 |       const t = _('2020-08-06T03:48:10.258Z').tz(TOKYO)
    > 117 |       expect(t.format('Z')).toBe('+09:00')
      118 |     })
      119 |   })
      120 | })
      
      at forEach (test/plugin/timezone.test.js:117:29)
          at Array.forEach (<anonymous>)
      at Object.<anonymous> (test/plugin/timezone.test.js:115:21)

  ● DST, a time that never existed Spring Forward › 2012-03-11 02:00:00

    expect(received).toBe(expected) // Object.is equality
    
    Expected value to be:
      "2012-03-11T03:00:00-04:00"
    Received:
      "2012-03-11T04:00:00-04:00"

      143 |     const d = dayjs.tz(s, NY)
      144 |     const m = moment.tz(s, NY)
    > 145 |     expect(d.format()).toBe('2012-03-11T03:00:00-04:00')
      146 |     expect(d.format()).toBe(m.format())
      147 |     expect(d.valueOf()).toBe(m.valueOf())
      148 |     expect(d.valueOf()).toBe(1331449200000)
      
      at Object.<anonymous> (test/plugin/timezone.test.js:145:24)

  ● DST, a time that never existed Spring Forward › 2012-03-11 02:59:59

    expect(received).toBe(expected) // Object.is equality
    
    Expected value to be:
      "2012-03-11T03:59:59-04:00"
    Received:
      "2012-03-11T04:59:59-04:00"

      154 |     const d = dayjs.tz(s, NY)
      155 |     const m = moment.tz(s, NY)
    > 156 |     expect(d.format()).toBe('2012-03-11T03:59:59-04:00')
      157 |     expect(d.format()).toBe(m.format())
      158 |     expect(d.valueOf()).toBe(m.valueOf())
      159 |     expect(d.valueOf()).toBe(1331452799000)
      
      at Object.<anonymous> (test/plugin/timezone.test.js:156:24)

  ● DST, a time that never existed Spring Forward › 2012-03-11 03:00:00

    expect(received).toBe(expected) // Object.is equality
    
    Expected value to be:
      "2012-03-11T03:00:00-04:00"
    Received:
      "2012-03-11T04:00:00-04:00"

      165 |     const d = dayjs.tz(s, NY)
      166 |     const m = moment.tz(s, NY)
    > 167 |     expect(d.format()).toBe('2012-03-11T03:00:00-04:00')
      168 |     expect(d.format()).toBe(m.format())
      169 |     expect(d.valueOf()).toBe(m.valueOf())
      170 |     expect(d.valueOf()).toBe(1331449200000)
      
      at Object.<anonymous> (test/plugin/timezone.test.js:167:24)

  ● DST, a time that never existed Fall Back › 2012-11-04 02:00:00

    expect(received).toBe(expected) // Object.is equality
    
    Expected value to be:
      "2012-11-04T02:00:00-05:00"
    Received:
      "2012-11-04T01:00:00-05:00"

      204 |     [dayjs, moment].forEach((_) => {
      205 |       const d = _.tz(s, NY)
    > 206 |       expect(d.format()).toBe('2012-11-04T02:00:00-05:00')
      207 |       expect(d.utcOffset()).toBe(-300)
      208 |       expect(d.valueOf()).toBe(1352012400000)
      209 |     })
      
      at forEach (test/plugin/timezone.test.js:206:26)
          at Array.forEach (<anonymous>)
      at Object.<anonymous> (test/plugin/timezone.test.js:204:21)


Test Suites: 3 failed, 63 passed, 66 total
Tests:       12 failed, 601 passed, 613 total
Snapshots:   0 total
Time:        12.936s
Ran all test suites.

@addisonElliott
Copy link

This bug sounds similar to the recent comment in this one: #1340 (comment)

I'm going to cross-post the bug and how it can be fixed. Let me know if that doesn't actually fix this.

Not sure your bug is similar to the OPs, unless I'm missing the connection.

But I did confirm and figure out what the problem is with your case. It's actually a pretty easy fix (I think).

The problem

I'm in CST, which has an offset of -5/-6 (depending on DST). Let's use this as an example.

Given the input you gave: 2020-03-29T00:30:00Z

The code converts to local machines timezone (at this time it was -5 for me). Then it converts to the desired timezone. These are the results:

  • 2020-03-28T20:30:00-05:00
  • 2020-03-29T03:30:00+02:00

Then these two dates are subtracted (disregard the offset), giving -07:00. Next, we take local machine offset (-5) and subtract from -7. -5 - (-7) = +2. Correct answer.

That's how it should work. Let's look at the code and I'll show you the bug.

  proto.tz = function (timezone = defaultTimezone, keepLocalTime) {
    const oldOffset = this.utcOffset()
    const target = this.toDate().toLocaleString('en-US', { timeZone: timezone })
    const diff = Math.round((this.toDate() - new Date(target)) / 1000 / 60)
    let ins = d(target).$set(MS, this.$ms).utcOffset(localUtcOffset - diff, true)
    if (keepLocalTime) {
      const newOffset = ins.utcOffset()
      ins = ins.add(oldOffset - newOffset, MIN)
    }
    ins.$x.$timezone = timezone
    return ins
  }

Source: https://github.com/iamkun/dayjs/blob/dev/src/plugin/timezone/index.js#L101

Check out that it takes localUtcOffset and subtracts the diff. That localUtcOffset is obtained by doing the following. The problem is that DST is applied now so the offset for me is -06:00, giving the offset of +01:00 that we're seeing.

  const localUtcOffset = d().utcOffset()

Source: https://github.com/iamkun/dayjs/blob/dev/src/plugin/timezone/index.js#L39

The fix

Replace localUtcOffset with this.utcOffset() and that will return the UTC offset at that date

What you should do

I haven't tested this but I think it'll work.

If that works for you, I'd encourage you to submit a PR and fix this.

When was the bug introduced

Bug has existed ever since the timezone plugin was added.

https://github.com/iamkun/dayjs/pull/974/files

@addisonElliott
Copy link

A fix was applied in #1352 that may fix this bug. Can someone try with the latest changes and see if the issue still persists?

@lucasrcosta
Copy link

Still brakes here, although a little different...

Summary of all failing tests
 FAIL  test/plugin/timezone.test.js (5.167s)
  ● Convert › convert to target time

    expect(received).toBe(expected) // Object.is equality
    
    Expected value to be:
      1401624000000
    Received:
      1401620400000

      76 |     expect(losAngeles.format()).toBe('2014-06-01T05:00:00-07:00')
      77 |     expect(losAngeles.format()).toBe(MlosAngeles.format())
    > 78 |     expect(losAngeles.valueOf()).toBe(1401624000000)
      79 |     expect(losAngeles.valueOf()).toBe(MlosAngeles.valueOf())
      80 |     expect(losAngeles.utcOffset()).toBe(-420)
      81 |     expect(losAngeles.utcOffset()).toBe(MlosAngeles.utcOffset())
      
      at Object.<anonymous> (test/plugin/timezone.test.js:78:34)

  ● Convert › convert to target time

    expect(received).toBe(expected) // Object.is equality
    
    Expected value to be:
      1401624000000
    Received:
      1401620400000

      86 |       const losAngeles = _('2014-06-01T12:00:00Z').tz('America/Los_Angeles')
      87 |       expect(losAngeles.format()).toBe('2014-06-01T05:00:00-07:00')
    > 88 |       expect(losAngeles.valueOf()).toBe(1401624000000)
      89 |     })
      90 |   })
      91 | 
      
      at forEach (test/plugin/timezone.test.js:88:36)
          at Array.forEach (<anonymous>)
      at Object.<anonymous> (test/plugin/timezone.test.js:85:21)

  ● DST, a time that never existed Spring Forward › 2012-03-11 02:00:00

    expect(received).toBe(expected) // Object.is equality
    
    Expected value to be:
      "2012-03-11T03:00:00-04:00"
    Received:
      "2012-03-11T04:00:00-04:00"

      145 |     const d = dayjs.tz(s, NY)
      146 |     const m = moment.tz(s, NY)
    > 147 |     expect(d.format()).toBe('2012-03-11T03:00:00-04:00')
      148 |     expect(d.format()).toBe(m.format())
      149 |     expect(d.valueOf()).toBe(m.valueOf())
      150 |     expect(d.valueOf()).toBe(1331449200000)
      
      at Object.<anonymous> (test/plugin/timezone.test.js:147:24)

  ● DST, a time that never existed Spring Forward › 2012-03-11 02:59:59

    expect(received).toBe(expected) // Object.is equality
    
    Expected value to be:
      "2012-03-11T03:59:59-04:00"
    Received:
      "2012-03-11T04:59:59-04:00"

      156 |     const d = dayjs.tz(s, NY)
      157 |     const m = moment.tz(s, NY)
    > 158 |     expect(d.format()).toBe('2012-03-11T03:59:59-04:00')
      159 |     expect(d.format()).toBe(m.format())
      160 |     expect(d.valueOf()).toBe(m.valueOf())
      161 |     expect(d.valueOf()).toBe(1331452799000)
      
      at Object.<anonymous> (test/plugin/timezone.test.js:158:24)

  ● DST, a time that never existed Spring Forward › 2012-03-11 03:00:00

    expect(received).toBe(expected) // Object.is equality
    
    Expected value to be:
      "2012-03-11T03:00:00-04:00"
    Received:
      "2012-03-11T04:00:00-04:00"

      167 |     const d = dayjs.tz(s, NY)
      168 |     const m = moment.tz(s, NY)
    > 169 |     expect(d.format()).toBe('2012-03-11T03:00:00-04:00')
      170 |     expect(d.format()).toBe(m.format())
      171 |     expect(d.valueOf()).toBe(m.valueOf())
      172 |     expect(d.valueOf()).toBe(1331449200000)
      
      at Object.<anonymous> (test/plugin/timezone.test.js:169:24)

  ● DST, a time that never existed Fall Back › 2012-11-04 02:00:00

    expect(received).toBe(expected) // Object.is equality
    
    Expected value to be:
      "2012-11-04T02:00:00-05:00"
    Received:
      "2012-11-04T01:00:00-05:00"

      206 |     [dayjs, moment].forEach((_) => {
      207 |       const d = _.tz(s, NY)
    > 208 |       expect(d.format()).toBe('2012-11-04T02:00:00-05:00')
      209 |       expect(d.utcOffset()).toBe(-300)
      210 |       expect(d.valueOf()).toBe(1352012400000)
      211 |     })
      
      at forEach (test/plugin/timezone.test.js:208:26)
          at Array.forEach (<anonymous>)
      at Object.<anonymous> (test/plugin/timezone.test.js:206:21)

 FAIL  test/plugin/localizedFormat.test.js
  ● Should not interpolate characters inside square brackets

    expect(received).toBe(expected) // Object.is equality
    
    Expected value to be:
      "1970 l 1970"
    Received:
      "1969 l 1969"

      29 | 
      30 |   expect(actualDate.format('[l]')).toBe('l')
    > 31 |   expect(actualDate.format('YYYY [l] YYYY')).toBe('1970 l 1970')
      32 |   expect(actualDate.format('l [l] l')).toBe('1/1/1970 l 1/1/1970')
      33 |   expect(actualDate.format('[L LL LLL LLLL]')).toBe(expectedDate.format('[L LL LLL LLLL]'))
      34 | 
      
      at Object.<anonymous> (test/plugin/localizedFormat.test.js:31:46)

 FAIL  test/plugin/dayOfYear.test.js
  ● DayOfYear set

    expect(received).toBe(expected) // Object.is equality
    
    Expected value to be:
      "2015-01-04T00:00:00.000Z"
    Received:
      "2014-01-05T00:00:00.000Z"

      31 |   expect(dayjs('2015-01-01T00:00:00.000Z')
      32 |     .dayOfYear(4)
    > 33 |     .toISOString()).toBe('2015-01-04T00:00:00.000Z')
      34 | 
      35 |   expect(dayjs('2015-01-01T00:00:00.000Z')
      36 |     .dayOfYear(32)
      
      at Object.<anonymous> (test/plugin/dayOfYear.test.js:33:21)


Test Suites: 3 failed, 68 passed, 71 total
Tests:       8 failed, 648 passed, 656 total
Snapshots:   0 total
Time:        12.402s
Ran all test suites.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

dayjs on  dev is 📦 v0.0.0-development took 20s 982ms 
➜ git pull
Already up to date.```

@sts-ryan-holton
Copy link

I'm getting the same problem now that we're in BST, I'm in Europe/London timezone and this is what I'm getting:

  • Date Time: 2021-04-15 14:00:00
  • console.log(this.$dayjs.tz('2021-04-15 14:00:00', 'UTC').toISOString()) // gives 2021-04-15 14:00:00
  • console.log(this.$dayjs.tz('2021-04-15 14:00:00', 'Europe/London').toISOString()) // gives 2021-04-15 13:00:00

Clearly wrong, any suggestions?

@hhamud
Copy link

hhamud commented May 18, 2021

Has this been fixed?. I am having the same issue with a few different time zones that apply daylight savings time, or has anyone been successful with any work around?,

@addisonElliott
Copy link

It sounds like it hasn't. I thought #1352 would fix it but others have reported not. Note that these changes are not officially released. In other words, you have to use the dev branch in order to get the latest changes.

If you're interested, try with the dev branch and see if it's still broken

@hhamud
Copy link

hhamud commented May 18, 2021

It sounds like it hasn't. I thought #1352 would fix it but others have reported not. Note that these changes are not officially released. In other words, you have to use the dev branch in order to get the latest changes.

If you're interested, try with the dev branch and see if it's still broken

Thanks for the tip. I've tried to install the dev branch however it still does not fix my issue.

@dobeerman
Copy link

Seems the issue still in place.

I tried to run this script in different time zones and got quite diverged results.

console.log(dayjs("2027-10-31T00:00:00Z").tz("Europe/Berlin").format());

console.log(dayjs("2027-10-31T01:00:00Z").tz("Europe/Berlin").format()); // +1hr

ServerTime: Wed Sep 15 2021 08:14:59 GMT+0200 (Central European Summer Time)

2027-10-31T02:00:00+02:00
2027-10-31T02:00:00Z

ServerTime: Wed Sep 15 2021 07:15:53 GMT+0100 (British Summer Time)

2027-10-31T02:00:00+03:00
2027-10-31T02:00:00+01:00

ServerTime: Wed Sep 15 2021 16:16:46 GMT+1000 (Vladivostok Standard Time)

2027-10-31T02:00:00+02:00
2027-10-31T02:00:00+01:00

This issue affects also development process when remote developers run it on their own local machines across the world.

I expect to have the same result which is not related to the server's timezone.

Please correct me if I'm wrong.

@CoreyKovalik
Copy link

CoreyKovalik commented Oct 29, 2021

Seems related to #1412

and also related to: #1408

@Serg-Mois
Copy link

The problem is still relevant.

@CoreyKovalik
Copy link

The problem is still relevant.

Last November we moved from dayjs to luxon and never looked back. This March we now have no issues traversing the DST boundary :)

@Serg-Mois
Copy link

The problem is still relevant.

Last November we moved from dayjs to luxon and never looked back. This March we now have no issues traversing the DST boundary :)

@CoreyKovalik we have a big project, it will be much longer to switch to luxon, due to the API differences.

@AComasSamcla
Copy link

a year and a half after this bug was reported and it's still no fixed? damn... should i revert to momentjs after all?

@Serg-Mois
Copy link

@AComasSamcla I didn't check, but looks like fixed in https://github.com/iamkun/dayjs/releases/tag/v1.11.2

fix UTC plugin .valueOf not taking DST into account (#1448) (27d1c50)

@AComasSamcla
Copy link

@Serg-Mois oh nice, i checked it and seems fixed now, so probably this issue could be closed by @iamkun too.
Thanks!

@thomasnal
Copy link

thomasnal commented Nov 19, 2022

The issue remains,

    "dayjs": {
      "version": "1.11.5",

EDIT: updated to 1.11.6, the issue remains.

dayjs.utc("2022-04-22 15:08:45").unix() // wrong, expected: 1650640125, actual: 1650636525 
dayjs.utc("2022-08-22 15:08:45").unix() // wrong, expected: 1661180925, actual: 1661177325
dayjs.utc("2022-01-22 15:08:45").unix() // ok, expected: 1642864125, actual: 1642864125

Verified with unixtimestamp.com and python.

EDIT2: If the time is specified this way then the conversion is correct,

dayjs.utc("2022-04-22T15:08:45.000Z").unix() // ok, expected: 1650640125, actual: 1650640125

@WarrenBuffering
Copy link

was there ever a solution for this?

@jonah-ullman
Copy link

Just noting that this is still an issue in 1.11.10

@sanket-mundada
Copy link

Any updates on this issue? Still facing the same in latest version

@vladimircosta11
Copy link

I am with the same problem.

@Aki0x137
Copy link

Same here, facing issues with DST handling.

@nabak9
Copy link

nabak9 commented Jul 23, 2024

It's been almost 4 years and still no fix.. I just came across the same issue.
It's happening when subtracting 6 months, off by 1 hour

@njoshi22
Copy link

Ha, I came across the same issue and couldn't figure it out until reading this --- is this still not fixed?

@amir-huseinspahic
Copy link

I'm not sure if I got this wrong, but for whatever reason setting the 'keepLocalTime' to 'false' will correctly display the time in regions affected by DST.

I have a function like this:

    function getHRT(datetime) {
        return dayjs(datetime)
            .tz(timezone, false) // Put the 'false' here when setting the timezone.
            .format(date_format + ', ' + time_format);
    }

I'm working with a VILT stack, not sure if that has anything to do with it.
Can someone else please confirm?

@triemstr
Copy link

@amir-huseinspahic I don't think it is meant for that. See when keepLocalTime was introduced: #1149

It seems to me that if you want to say it is 6:00 in timezone 1 and want to change it to 6:00 in timezone 2, then pass in keepLocalTime = true. Otherwise, it will change the time to match the same moment 6:00 in timezone 1.

If keepLocalTime works, that's interesting, but it may not always.

@triemstr
Copy link

triemstr commented Sep 17, 2024

Workaround for me due to confusion on timezones is to use Date directly for this purpose (which I only need in one spot in my code) whereas I use dayjs in many areas.

const date1 = new Date('December 1, 1975 23:15:30 GMT');
const date2 = new Date('August 1, 1975 23:15:30 GMT');
const date3 = new Date('January 1, 1975 23:15:30 GMT');

console.log(date1.getTimezoneOffset());
// Expected output: your local timezone offset in minutes from GMT
// In Pacific time (your results will vary): 480.

console.log(date2.getTimezoneOffset());
// Expected output: your local timezone offset in minutes from GMT
// In Pacific time (your results will vary): 420.

console.log(date1.getTimezoneOffset() === date2.getTimezoneOffset());
// Expected output: false -- Since different offsets due to daylight savings in summer.

console.log(date1.getTimezoneOffset() === date3.getTimezoneOffset());
// Expected output: true -- Same offset in winter despite two different winter dates.

tl;dr - I really just use this only in my code:

const tzOffsetHours = new Date().getTimezoneOffset()/60;
console.log(tzOffsetHours);
// Expected output today, September 17, 2024 (still daylight savings) in the Pacific Time zone in hours: 7

You could instead pull your dayjs formatted date and put into the Date object or compare to the system time somehow or find some other way to use the IANA database if issues with dayjs until dayjs is updated. I played with Date code here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset

Another workaround: #1388 (comment)

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