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("2013-11-18T11:55:20").tz("America/Toronto") does not work #2102

Open
tukusejssirs opened this issue Oct 29, 2022 · 11 comments
Open

dayjs("2013-11-18T11:55:20").tz("America/Toronto") does not work #2102

tukusejssirs opened this issue Oct 29, 2022 · 11 comments

Comments

@tukusejssirs
Copy link
Contributor

tukusejssirs commented Oct 29, 2022

Describe the bug
dayjs("2013-11-18T11:55:20").tz("America/Toronto") (as suggested in the docs) outputs the following:

const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
const timezone = require('dayjs/plugin/timezone')
dayjs.extend(utc)
dayjs.extend(timezone)

console.log(dayjs('2013-11-18T11:55:20').tz('America/Toronto'))

// Output
{
  '$L': 'en',
  '$d': Invalid Date,
  '$x': { '$timezone': 'America/Toronto' },
  '$y': NaN,
  '$M': NaN,
  '$D': NaN,
  '$W': NaN,
  '$H': NaN,
  '$m': NaN,
  '$s': NaN,
  '$ms': NaN,
  '$offset': NaN,
  '$u': false
}

Expected behavior

The following should be the output:

{
  '$L': 'en',
  '$d': 2013-11-18T10:55:20.000Z,
  '$x': { '$localOffset': -60, '$timezone': 'America/Toronto' },
  '$y': 2013,
  '$M': 10,
  '$D': 18,
  '$W': 1,
  '$H': 11,
  '$m': 55,
  '$s': 20,
  '$ms': 0,
  '$offset': -300
}

Information

  • Day.js Version: 1.11.6, 1.11.0, 1.10.0, 1.9.0 (it seems like the bug is in all versions since utc plugin was introduced)
  • OS: [e.g. iOS]: Arch Linux
  • Browser [e.g. chrome 62]: n/a
  • Time zone: [e.g. GMT-07:00 DST (Pacific Daylight Time)]: tested with America/Toronto and Europe/Slovakia; I don’t think it matters;
  • Node version: 19.0.0
  • NPM version: 8.19.2
@UmidbekU
Copy link

I have the same problem on android.

@sys-256
Copy link

sys-256 commented Oct 30, 2022

Same here. NodeJS v16.16.0 and Linux (kernel version: 6.0.5-arch1-1)

@19424056
Copy link

19424056 commented Nov 2, 2022

I have the same problem on android.

@BePo65
Copy link
Contributor

BePo65 commented Nov 6, 2022

Very strange; tried it on windows and on ubuntu 20.04 and in all cases my tests using @tukusejssirs code succeeded (no invalid date).

Additionally I created 3 tests in dayjs and got the same results as moment does (even here: no invalid date).

My environment was dayjs 1.11.6 on node v14.19.2 on linux, respective node 16.18.0 on windows.

@tukusejssirs
Copy link
Contributor Author

tukusejssirs commented Nov 6, 2022

Okay, I re-tested this with dayjs@1.11.6 and various version of node (v16.15.1+) and npm (v8.11.0+), changing versions using nvm: all succeed (i.e. no invalid date returned).

However, whenever I used the system version (installed on Arch Linux via pacman/yay), it fails. I have installed npm@8.19.2 and node@19.0.1 and it fails to produce a valid date, however, when I use the same versions installed via nvm, it succeed.

I have no idea what is the difference between them.

@19424056
Copy link

19424056 commented Nov 9, 2022

I have the same problem on android.
Day.js Version: 1.11.6
RN: 0.70.4

dayjs.extend(utc)
dayjs.extend(timezone)

dayjs.tz("2013-11-18 11:55:20", "America/Toronto") // '2013-11-18T11:55:20-05:00'
dayjs("2013-11-18 11:55:20").tz("America/Toronto") // null

please help me .

@BePo65
Copy link
Contributor

BePo65 commented Nov 10, 2022

@tukusejssirs so this looks more like an issue for yay.

@19424056 sorry, but I don't have an android test environment nor did I ever make developments in an android environment. Perhaps the tip from @tukusejssirs helps (installing dayjs via npm).

@19424056
Copy link

@BePo65 i try to install dayjs via npm but not work :(
dayjs("2013-11-18 11:55:20").tz("America/Toronto") // null

@galenhuntington
Copy link

The problem appears to be here:

const target = date.toLocaleString('en-US', { timeZone: timezone })
const diff = Math.round((date - new Date(target)) / 1000 / 60)

The offset is calculated by converting a Date to an en-US locale string, then back again to a Date. However, the conversion back fails in some environments:

> new Date().toLocaleString('en-US', { timeZone: "America/Boise" })
'11/18/2022, 1:27:14 PM'
> new Date('11/18/2022, 1:27:14 PM')
Invalid Date

This may depend on obscure details of the OS you're running on.

For some other locales this works without issue:

> new Date().toLocaleString('zh', { timeZone: "America/Boise" })
'2022/11/18 13:28:30'
> new Date('2022/11/18 13:28:30')
2022-11-18T13:28:30.000Z

@tukusejssirs
Copy link
Contributor Author

Thanks, @galenhuntington!

If you are right, I think the solution could be to use new Date('2022-11-18T22:00:00.000+01:00') to encode 18 Nov 2022, 22:00 in Europe/Bratislava timezone. First we would need to get the timezone offset from IANA timezone name, as Date does not accept IANA timezone name, which is quite easy (I had a similar requirement when I coded setLocalTime() function in my SO answer). I really simplified this, it might be useful to use some other parts of my setLocatTime() function in order to cover all corner cases.

/**
 * Get timezone offset
 *
 * @param      {Date}    date      Date
 * @param      {string}  timezone  Timezone
 * @return     {string}  Timezone offset
 */
function getTimezoneOffset({date, timezone}) {
  return new Intl
    .DateTimeFormat('en-US', {timeZone: timezone, timeZoneName: 'longOffset'})
    .formatToParts(date)
    .find(i => i.type === 'timeZoneName').value.match(/[\d+:-]+$/)?.[0]
}

console.log(getTimezoneOffset({date: new Date('2022-11-18T21:00:00.000Z'), timezone: 'Europe/Bratislava'}))
// Output
// '+01:00'

@rpellerin
Copy link

The issue is known and tracked there:

NodeJS fix: nodejs/node#45573

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

7 participants