Skip to content

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

Open
@tukusejssirs

Description

@tukusejssirs

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

Activity

UmidbekU

UmidbekU commented on Oct 29, 2022

@UmidbekU

I have the same problem on android.

sys-256

sys-256 commented on Oct 30, 2022

@sys-256

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

19424056

19424056 commented on Nov 2, 2022

@19424056

I have the same problem on android.

BePo65

BePo65 commented on Nov 6, 2022

@BePo65
Contributor

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

tukusejssirs commented on Nov 6, 2022

@tukusejssirs
ContributorAuthor

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

19424056 commented on Nov 9, 2022

@19424056

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

BePo65 commented on Nov 10, 2022

@BePo65
Contributor

@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

19424056 commented on Nov 11, 2022

@19424056

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

galenhuntington

galenhuntington commented on Nov 18, 2022

@galenhuntington

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

tukusejssirs commented on Nov 18, 2022

@tukusejssirs
ContributorAuthor

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'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

      Participants

      @galenhuntington@tukusejssirs@rpellerin@BePo65@UmidbekU

      Issue actions

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