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.63k stars 2.28k forks source link

System's timezone isn't correctly recognized/handled #1029

Open avendiart opened 4 years ago

avendiart commented 4 years ago

Describe the bug While working with dayjs and the timezone plugin I've noticed incorrect handling of timezones. Checking out the repository and running tests locally in a container results in some tests failing, which I suppose is the reason for the bug I've encountered in development under Node 12.18.0

Expected behavior Tests passing.

Information

docker-compose.yml used to check out the repository:

version: "3.7"

services:
  dev:
    image: node:12.18.0-buster
    command: /bin/sh -c "while sleep 1000; do :; done"
    working_dir: /workspace
    volumes:
      - workspace:/workspace:cached

Steps with complete logs:

root@f2864ee8e0ca:/workspace/dayjs# export TZ=Europe/Berlin
root@f2864ee8e0ca:/workspace/dayjs# date
Fri Aug 28 17:29:51 CEST 2020
root@f2864ee8e0ca:/workspace/dayjs# npm test

> dayjs@0.0.0-development test /workspace/dayjs
> TZ=Pacific/Auckland npm run test-tz && TZ=Europe/London npm run test-tz && TZ=America/Whitehorse npm run test-tz && npm run test-tz && jest

> dayjs@0.0.0-development test-tz /workspace/dayjs
> date && jest test/timezone.test --coverage=false

Sat Aug 29 03:29:55 NZST 2020
 PASS  test/timezone.test.js
  ✓ Add Time days (DST) (5ms)
  ✓ Utc Offset (3ms)
  ✓ Diff (DST) (4ms)
  ✓ UTC add day in DST (1ms)

Test Suites: 1 passed, 1 total
Tests:       4 passed, 4 total
Snapshots:   0 total
Time:        0.511s, estimated 1s
Ran all test suites matching /test\/timezone.test/i.

> dayjs@0.0.0-development test-tz /workspace/dayjs
> date && jest test/timezone.test --coverage=false

Fri Aug 28 16:29:56 BST 2020
 PASS  test/timezone.test.js
  ✓ Add Time days (DST) (9ms)
  ✓ Utc Offset (1ms)
  ✓ Diff (DST) (4ms)
  ✓ UTC add day in DST (1ms)

Test Suites: 1 passed, 1 total
Tests:       4 passed, 4 total
Snapshots:   0 total
Time:        0.51s, estimated 1s
Ran all test suites matching /test\/timezone.test/i.

> dayjs@0.0.0-development test-tz /workspace/dayjs
> date && jest test/timezone.test --coverage=false

Fri Aug 28 08:29:56 MST 2020
 PASS  test/timezone.test.js
  ✓ Add Time days (DST) (6ms)
  ✓ Utc Offset (4ms)
  ✓ Diff (DST) (4ms)
  ✓ UTC add day in DST (1ms)

Test Suites: 1 passed, 1 total
Tests:       4 passed, 4 total
Snapshots:   0 total
Time:        0.513s, estimated 1s
Ran all test suites matching /test\/timezone.test/i.

> dayjs@0.0.0-development test-tz /workspace/dayjs
> date && jest test/timezone.test --coverage=false

Fri Aug 28 17:29:57 CEST 2020
 PASS  test/timezone.test.js
  ✓ Add Time days (DST) (5ms)
  ✓ Utc Offset (5ms)
  ✓ Diff (DST) (4ms)
  ✓ UTC add day in DST (1ms)

Test Suites: 1 passed, 1 total
Tests:       4 passed, 4 total
Snapshots:   0 total
Time:        0.512s, estimated 1s
Ran all test suites matching /test\/timezone.test/i.
 PASS  test/comparison.test.js
 PASS  test/plugin/utc.test.js
 PASS  test/plugin/localeData.test.js
 FAIL  test/plugin/badMutable.test.js
  ● WeekOfYear get week won"t change instance

    expect(received).toBe(expected) // Object.is equality

    Expected value to be:
      "2020-08-28T17:29:59+02:00"
    Received:
      "2019-05-28T17:29:59+02:00"

      183 |   const format = d.format()
      184 |   d.week()
    > 185 |   expect(d.format()).toBe(format)
      186 | })
      187 | 

      at Object.<anonymous> (test/plugin/badMutable.test.js:185:22)

 PASS  test/plugin/duration.test.js
 FAIL  test/plugin/utc-utcOffset.test.js
  ● change hours when changing the utc offset in UTC mode

    expect(received).toBe(expected) // Object.is equality

    Expected value to be:
      5
    Received:
      4

      87 |   expect(d.hour()).toBe(6)
      88 |   expect(d.utcOffset(0).hour()).toBe(6)
    > 89 |   expect(d.utcOffset(-60).hour()).toBe(5)
      90 |   expect(d.utcOffset(60).hour()).toBe(7)
      91 |   expect(d.utcOffset(-30).format('HH:mm')).toBe('06:01')
      92 |   expect(d.utcOffset(30).format('HH:mm')).toBe('07:01')

      at Object.<anonymous> (test/plugin/utc-utcOffset.test.js:89:35)

  ● keep hours when adding month in offset mode

    expect(received).toBe(expected) // Object.is equality

    Expected value to be:
      6
    Received:
      5

      111 |   const dm8 = dayjs('2000-01-30T06:31:00-08:00').utcOffset(-8)
      112 | 
    > 113 |   expect(d10.add(1, 'month').hour()).toBe(6)
      114 |   expect(dm8.add(1, 'month').hour()).toBe(6)
      115 | 
      116 |   expect(d10.add(-2, 'month').hour()).toBe(6)

      at Object.<anonymous> (test/plugin/utc-utcOffset.test.js:113:38)

 PASS  test/plugin/objectSupport.test.js
 PASS  test/plugin/isoWeek.test.js
 PASS  test/plugin/customParseFormat.test.js
 PASS  test/plugin/isSameOrBefore.test.js
 PASS  test/plugin/pluralGetSet.test.js
 PASS  test/parse.test.js
 PASS  test/display.test.js
 PASS  test/timezone.test.js
 PASS  test/locale/et.test.js
 PASS  test/plugin/weekOfYear.test.js
 FAIL  test/plugin/timezone.test.js
  ● DST, a time that never existed Spring Forward › 2012-03-11 01:59:59

    expect(received).toBe(expected) // Object.is equality

    Expected value to be:
      "2012-03-11T01:59:59-05:00"
    Received:
      "2012-03-11T00:59:59-05:00"

      122 |     const d = dayjs.tz(s, NY)
      123 |     const m = moment.tz(s, NY)
    > 124 |     expect(d.format()).toBe('2012-03-11T01:59:59-05:00')
      125 |     expect(d.format()).toBe(m.format())
      126 |     expect(d.utcOffset()).toBe(-300)
      127 |     expect(d.utcOffset()).toBe(m.utcOffset())

      at Object.<anonymous> (test/plugin/timezone.test.js:124:24)

  ● 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-11T02:00:00-04:00"

      133 |     const d = dayjs.tz(s, NY)
      134 |     const m = moment.tz(s, NY)
    > 135 |     expect(d.format()).toBe('2012-03-11T03:00:00-04:00')
      136 |     expect(d.format()).toBe(m.format())
      137 |     expect(d.valueOf()).toBe(m.valueOf())
      138 |     expect(d.valueOf()).toBe(1331449200000)

      at Object.<anonymous> (test/plugin/timezone.test.js:135: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-11T02:59:59-04:00"

      144 |     const d = dayjs.tz(s, NY)
      145 |     const m = moment.tz(s, NY)
    > 146 |     expect(d.format()).toBe('2012-03-11T03:59:59-04:00')
      147 |     expect(d.format()).toBe(m.format())
      148 |     expect(d.valueOf()).toBe(m.valueOf())
      149 |     expect(d.valueOf()).toBe(1331452799000)

      at Object.<anonymous> (test/plugin/timezone.test.js:146: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-11T02:00:00-04:00"

      155 |     const d = dayjs.tz(s, NY)
      156 |     const m = moment.tz(s, NY)
    > 157 |     expect(d.format()).toBe('2012-03-11T03:00:00-04:00')
      158 |     expect(d.format()).toBe(m.format())
      159 |     expect(d.valueOf()).toBe(m.valueOf())
      160 |     expect(d.valueOf()).toBe(1331449200000)

      at Object.<anonymous> (test/plugin/timezone.test.js:157:24)

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

    expect(received).toBe(expected) // Object.is equality

    Expected value to be:
      "2012-11-04T00:59:59-04:00"
    Received:
      "2012-11-03T23:59:59-04:00"

      171 |     [dayjs, moment].forEach((_) => {
      172 |       const d = _.tz(s, NY)
    > 173 |       expect(d.format()).toBe('2012-11-04T00:59:59-04:00')
      174 |       expect(d.utcOffset()).toBe(-240)
      175 |       expect(d.valueOf()).toBe(1352005199000)
      176 |     })

      at forEach (test/plugin/timezone.test.js:173:26)
          at Array.forEach (<anonymous>)
      at Object.<anonymous> (test/plugin/timezone.test.js:171:21)

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

    expect(received).toBe(expected) // Object.is equality

    Expected value to be:
      "2012-11-04T01:00:00-04:00"
    Received:
      "2012-11-04T00:00:00-04:00"

      180 |     [dayjs, moment].forEach((_) => {
      181 |       const d = _.tz(s, NY)
    > 182 |       expect(d.format()).toBe('2012-11-04T01:00:00-04:00')
      183 |       expect(d.utcOffset()).toBe(-240)
      184 |       expect(d.valueOf()).toBe(1352005200000)
      185 |     })

      at forEach (test/plugin/timezone.test.js:182:26)
          at Array.forEach (<anonymous>)
      at Object.<anonymous> (test/plugin/timezone.test.js:180:21)

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

    expect(received).toBe(expected) // Object.is equality

    Expected value to be:
      "2012-11-04T01:59:59-04:00"
    Received:
      "2012-11-04T00:59:59-04:00"

      189 |     [dayjs, moment].forEach((_) => {
      190 |       const d = _.tz(s, NY)
    > 191 |       expect(d.format()).toBe('2012-11-04T01:59:59-04:00')
      192 |       expect(d.utcOffset()).toBe(-240)
      193 |       expect(d.valueOf()).toBe(1352008799000)
      194 |     })

      at forEach (test/plugin/timezone.test.js:191:26)
          at Array.forEach (<anonymous>)
      at Object.<anonymous> (test/plugin/timezone.test.js:189:21)

  ● 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"

      198 |     [dayjs, moment].forEach((_) => {
      199 |       const d = _.tz(s, NY)
    > 200 |       expect(d.format()).toBe('2012-11-04T02:00:00-05:00')
      201 |       expect(d.utcOffset()).toBe(-300)
      202 |       expect(d.valueOf()).toBe(1352012400000)
      203 |     })

      at forEach (test/plugin/timezone.test.js:200:26)
          at Array.forEach (<anonymous>)
      at Object.<anonymous> (test/plugin/timezone.test.js:198:21)

 PASS  test/plugin/isBetween.test.js
 PASS  test/locale/uk.test.js
 PASS  test/plugin/calendar.test.js
 PASS  test/locale/pl.test.js
 PASS  test/locale/fi.test.js
 PASS  test/locale/sk.test.js
 PASS  test/locale/ru.test.js
 PASS  test/plugin/isSameOrAfter.test.js
 PASS  test/plugin/relativeTime.test.js
 PASS  test/locale/cs.test.js
 PASS  test/query.test.js
 PASS  test/locale/en.test.js
 PASS  test/plugin/advancedFormat.test.js
 PASS  test/manipulate.test.js
 PASS  test/plugin/buddhistEra.test.js
 PASS  test/plugin/isoWeeksInYear.test.js
 PASS  test/plugin/updateLocale.test.js
 PASS  test/plugin/minMax.test.js
 PASS  test/plugin/weekday.test.js
 PASS  test/plugin/quarterOfYear.test.js
 PASS  test/locale/zh-cn.test.js
 PASS  test/plugin/declarations.test.js
 PASS  test/get-set.test.js
 PASS  test/plugin/localizedFormat.test.js
 PASS  test/plugin/isLeapYear.test.js
 PASS  test/locale.test.js
 PASS  test/utils.test.js
 PASS  test/locale/sv.test.js
 PASS  test/locale/zh.test.js
 PASS  test/plugin/dayOfYear.test.js
 PASS  test/plugin/weekYear.test.js
 PASS  test/plugin/toArray.test.js
 PASS  test/constructor.test.js
 PASS  test/plugin/isTomorrow.test.js
 PASS  test/plugin.test.js
 PASS  test/plugin/isToday.test.js
 PASS  test/plugin/isYesterday.test.js
 PASS  test/plugin/toObject.test.js
 PASS  test/plugin/isMoment.test.js
 PASS  test/locale/keys.test.js
------------------------------|----------|----------|----------|----------|-------------------|
File                          |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
------------------------------|----------|----------|----------|----------|-------------------|
All files                     |      100 |      100 |      100 |      100 |                   |
 src                          |      100 |      100 |      100 |      100 |                   |
  constant.js                 |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
  utils.js                    |      100 |      100 |      100 |      100 |                   |
 src/locale                   |      100 |      100 |      100 |      100 |                   |
  af.js                       |      100 |      100 |      100 |      100 |                   |
  ar-dz.js                    |      100 |      100 |      100 |      100 |                   |
  ar-kw.js                    |      100 |      100 |      100 |      100 |                   |
  ar-ly.js                    |      100 |      100 |      100 |      100 |                   |
  ar-ma.js                    |      100 |      100 |      100 |      100 |                   |
  ar-sa.js                    |      100 |      100 |      100 |      100 |                   |
  ar-tn.js                    |      100 |      100 |      100 |      100 |                   |
  ar.js                       |      100 |      100 |      100 |      100 |                   |
  az.js                       |      100 |      100 |      100 |      100 |                   |
  be.js                       |      100 |      100 |      100 |      100 |                   |
  bg.js                       |      100 |      100 |      100 |      100 |                   |
  bi.js                       |      100 |      100 |      100 |      100 |                   |
  bm.js                       |      100 |      100 |      100 |      100 |                   |
  bn.js                       |      100 |      100 |      100 |      100 |                   |
  bo.js                       |      100 |      100 |      100 |      100 |                   |
  br.js                       |      100 |      100 |      100 |      100 |                   |
  bs.js                       |      100 |      100 |      100 |      100 |                   |
  ca.js                       |      100 |      100 |      100 |      100 |                   |
  cs.js                       |      100 |      100 |      100 |      100 |                   |
  cv.js                       |      100 |      100 |      100 |      100 |                   |
  cy.js                       |      100 |      100 |      100 |      100 |                   |
  da.js                       |      100 |      100 |      100 |      100 |                   |
  de-at.js                    |      100 |      100 |      100 |      100 |                   |
  de-ch.js                    |      100 |      100 |      100 |      100 |                   |
  de.js                       |      100 |      100 |      100 |      100 |                   |
  dv.js                       |      100 |      100 |      100 |      100 |                   |
  el.js                       |      100 |      100 |      100 |      100 |                   |
  en-SG.js                    |      100 |      100 |      100 |      100 |                   |
  en-au.js                    |      100 |      100 |      100 |      100 |                   |
  en-ca.js                    |      100 |      100 |      100 |      100 |                   |
  en-gb.js                    |      100 |      100 |      100 |      100 |                   |
  en-ie.js                    |      100 |      100 |      100 |      100 |                   |
  en-il.js                    |      100 |      100 |      100 |      100 |                   |
  en-in.js                    |      100 |      100 |      100 |      100 |                   |
  en-nz.js                    |      100 |      100 |      100 |      100 |                   |
  en-tt.js                    |      100 |      100 |      100 |      100 |                   |
  en.js                       |      100 |      100 |      100 |      100 |                   |
  eo.js                       |      100 |      100 |      100 |      100 |                   |
  es-do.js                    |      100 |      100 |      100 |      100 |                   |
  es-pr.js                    |      100 |      100 |      100 |      100 |                   |
  es-us.js                    |      100 |      100 |      100 |      100 |                   |
  es.js                       |      100 |      100 |      100 |      100 |                   |
  et.js                       |      100 |      100 |      100 |      100 |                   |
  eu.js                       |      100 |      100 |      100 |      100 |                   |
  fa.js                       |      100 |      100 |      100 |      100 |                   |
  fi.js                       |      100 |      100 |      100 |      100 |                   |
  fo.js                       |      100 |      100 |      100 |      100 |                   |
  fr-ca.js                    |      100 |      100 |      100 |      100 |                   |
  fr-ch.js                    |      100 |      100 |      100 |      100 |                   |
  fr.js                       |      100 |      100 |      100 |      100 |                   |
  fy.js                       |      100 |      100 |      100 |      100 |                   |
  ga.js                       |      100 |      100 |      100 |      100 |                   |
  gd.js                       |      100 |      100 |      100 |      100 |                   |
  gl.js                       |      100 |      100 |      100 |      100 |                   |
  gom-latn.js                 |      100 |      100 |      100 |      100 |                   |
  gu.js                       |      100 |      100 |      100 |      100 |                   |
  he.js                       |      100 |      100 |      100 |      100 |                   |
  hi.js                       |      100 |      100 |      100 |      100 |                   |
  hr.js                       |      100 |      100 |      100 |      100 |                   |
  ht.js                       |      100 |      100 |      100 |      100 |                   |
  hu.js                       |      100 |      100 |      100 |      100 |                   |
  hy-am.js                    |      100 |      100 |      100 |      100 |                   |
  id.js                       |      100 |      100 |      100 |      100 |                   |
  is.js                       |      100 |      100 |      100 |      100 |                   |
  it-ch.js                    |      100 |      100 |      100 |      100 |                   |
  it.js                       |      100 |      100 |      100 |      100 |                   |
  ja.js                       |      100 |      100 |      100 |      100 |                   |
  jv.js                       |      100 |      100 |      100 |      100 |                   |
  ka.js                       |      100 |      100 |      100 |      100 |                   |
  kk.js                       |      100 |      100 |      100 |      100 |                   |
  km.js                       |      100 |      100 |      100 |      100 |                   |
  kn.js                       |      100 |      100 |      100 |      100 |                   |
  ko.js                       |      100 |      100 |      100 |      100 |                   |
  ku.js                       |      100 |      100 |      100 |      100 |                   |
  ky.js                       |      100 |      100 |      100 |      100 |                   |
  lb.js                       |      100 |      100 |      100 |      100 |                   |
  lo.js                       |      100 |      100 |      100 |      100 |                   |
  lt.js                       |      100 |      100 |      100 |      100 |                   |
  lv.js                       |      100 |      100 |      100 |      100 |                   |
  me.js                       |      100 |      100 |      100 |      100 |                   |
  mi.js                       |      100 |      100 |      100 |      100 |                   |
  mk.js                       |      100 |      100 |      100 |      100 |                   |
  ml.js                       |      100 |      100 |      100 |      100 |                   |
  mn.js                       |      100 |      100 |      100 |      100 |                   |
  mr.js                       |      100 |      100 |      100 |      100 |                   |
  ms-my.js                    |      100 |      100 |      100 |      100 |                   |
  ms.js                       |      100 |      100 |      100 |      100 |                   |
  mt.js                       |      100 |      100 |      100 |      100 |                   |
  my.js                       |      100 |      100 |      100 |      100 |                   |
  nb.js                       |      100 |      100 |      100 |      100 |                   |
  ne.js                       |      100 |      100 |      100 |      100 |                   |
  nl-be.js                    |      100 |      100 |      100 |      100 |                   |
  nl.js                       |      100 |      100 |      100 |      100 |                   |
  nn.js                       |      100 |      100 |      100 |      100 |                   |
  oc-lnc.js                   |      100 |      100 |      100 |      100 |                   |
  pa-in.js                    |      100 |      100 |      100 |      100 |                   |
  pl.js                       |      100 |      100 |      100 |      100 |                   |
  pt-br.js                    |      100 |      100 |      100 |      100 |                   |
  pt.js                       |      100 |      100 |      100 |      100 |                   |
  ro.js                       |      100 |      100 |      100 |      100 |                   |
  ru.js                       |      100 |      100 |      100 |      100 |                   |
  rw.js                       |      100 |      100 |      100 |      100 |                   |
  sd.js                       |      100 |      100 |      100 |      100 |                   |
  se.js                       |      100 |      100 |      100 |      100 |                   |
  si.js                       |      100 |      100 |      100 |      100 |                   |
  sk.js                       |      100 |      100 |      100 |      100 |                   |
  sl.js                       |      100 |      100 |      100 |      100 |                   |
  sq.js                       |      100 |      100 |      100 |      100 |                   |
  sr-cyrl.js                  |      100 |      100 |      100 |      100 |                   |
  sr.js                       |      100 |      100 |      100 |      100 |                   |
  ss.js                       |      100 |      100 |      100 |      100 |                   |
  sv.js                       |      100 |      100 |      100 |      100 |                   |
  sw.js                       |      100 |      100 |      100 |      100 |                   |
  ta.js                       |      100 |      100 |      100 |      100 |                   |
  te.js                       |      100 |      100 |      100 |      100 |                   |
  tet.js                      |      100 |      100 |      100 |      100 |                   |
  tg.js                       |      100 |      100 |      100 |      100 |                   |
  th.js                       |      100 |      100 |      100 |      100 |                   |
  tk.js                       |      100 |      100 |      100 |      100 |                   |
  tl-ph.js                    |      100 |      100 |      100 |      100 |                   |
  tlh.js                      |      100 |      100 |      100 |      100 |                   |
  tr.js                       |      100 |      100 |      100 |      100 |                   |
  tzl.js                      |      100 |      100 |      100 |      100 |                   |
  tzm-latn.js                 |      100 |      100 |      100 |      100 |                   |
  tzm.js                      |      100 |      100 |      100 |      100 |                   |
  ug-cn.js                    |      100 |      100 |      100 |      100 |                   |
  uk.js                       |      100 |      100 |      100 |      100 |                   |
  ur.js                       |      100 |      100 |      100 |      100 |                   |
  uz-latn.js                  |      100 |      100 |      100 |      100 |                   |
  uz.js                       |      100 |      100 |      100 |      100 |                   |
  vi.js                       |      100 |      100 |      100 |      100 |                   |
  x-pseudo.js                 |      100 |      100 |      100 |      100 |                   |
  yo.js                       |      100 |      100 |      100 |      100 |                   |
  zh-cn.js                    |      100 |      100 |      100 |      100 |                   |
  zh-hk.js                    |      100 |      100 |      100 |      100 |                   |
  zh-tw.js                    |      100 |      100 |      100 |      100 |                   |
  zh.js                       |      100 |      100 |      100 |      100 |                   |
 src/plugin/advancedFormat    |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/badMutable        |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/buddhistEra       |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/calendar          |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/customParseFormat |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/dayOfYear         |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/duration          |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/isBetween         |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/isLeapYear        |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/isMoment          |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/isSameOrAfter     |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/isSameOrBefore    |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/isToday           |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/isTomorrow        |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/isYesterday       |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/isoWeek           |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/isoWeeksInYear    |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/localeData        |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/localizedFormat   |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/minMax            |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/objectSupport     |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/pluralGetSet      |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/quarterOfYear     |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/relativeTime      |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/timezone          |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/toArray           |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/toObject          |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/updateLocale      |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/utc               |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/weekOfYear        |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/weekYear          |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
 src/plugin/weekday           |      100 |      100 |      100 |      100 |                   |
  index.js                    |      100 |      100 |      100 |      100 |                   |
------------------------------|----------|----------|----------|----------|-------------------|
Handlebars: Access has been denied to resolve the property "statements" because it is not an "own property" of its parent.
You can add a runtime option to disable the check or this warning:
See https://handlebarsjs.com/api-reference/runtime-options.html#options-to-control-prototype-access for details
Handlebars: Access has been denied to resolve the property "branches" because it is not an "own property" of its parent.
You can add a runtime option to disable the check or this warning:
See https://handlebarsjs.com/api-reference/runtime-options.html#options-to-control-prototype-access for details
Handlebars: Access has been denied to resolve the property "functions" because it is not an "own property" of its parent.
You can add a runtime option to disable the check or this warning:
See https://handlebarsjs.com/api-reference/runtime-options.html#options-to-control-prototype-access for details
Handlebars: Access has been denied to resolve the property "lines" because it is not an "own property" of its parent.
You can add a runtime option to disable the check or this warning:
See https://handlebarsjs.com/api-reference/runtime-options.html#options-to-control-prototype-access for details

Summary of all failing tests
 FAIL  test/plugin/badMutable.test.js
  ● WeekOfYear get week won"t change instance

    expect(received).toBe(expected) // Object.is equality

    Expected value to be:
      "2020-08-28T17:29:59+02:00"
    Received:
      "2019-05-28T17:29:59+02:00"

      183 |   const format = d.format()
      184 |   d.week()
    > 185 |   expect(d.format()).toBe(format)
      186 | })
      187 | 

      at Object.<anonymous> (test/plugin/badMutable.test.js:185:22)

 FAIL  test/plugin/utc-utcOffset.test.js
  ● change hours when changing the utc offset in UTC mode

    expect(received).toBe(expected) // Object.is equality

    Expected value to be:
      5
    Received:
      4

      87 |   expect(d.hour()).toBe(6)
      88 |   expect(d.utcOffset(0).hour()).toBe(6)
    > 89 |   expect(d.utcOffset(-60).hour()).toBe(5)
      90 |   expect(d.utcOffset(60).hour()).toBe(7)
      91 |   expect(d.utcOffset(-30).format('HH:mm')).toBe('06:01')
      92 |   expect(d.utcOffset(30).format('HH:mm')).toBe('07:01')

      at Object.<anonymous> (test/plugin/utc-utcOffset.test.js:89:35)

  ● keep hours when adding month in offset mode

    expect(received).toBe(expected) // Object.is equality

    Expected value to be:
      6
    Received:
      5

      111 |   const dm8 = dayjs('2000-01-30T06:31:00-08:00').utcOffset(-8)
      112 | 
    > 113 |   expect(d10.add(1, 'month').hour()).toBe(6)
      114 |   expect(dm8.add(1, 'month').hour()).toBe(6)
      115 | 
      116 |   expect(d10.add(-2, 'month').hour()).toBe(6)

      at Object.<anonymous> (test/plugin/utc-utcOffset.test.js:113:38)

 FAIL  test/plugin/timezone.test.js
  ● DST, a time that never existed Spring Forward › 2012-03-11 01:59:59

    expect(received).toBe(expected) // Object.is equality

    Expected value to be:
      "2012-03-11T01:59:59-05:00"
    Received:
      "2012-03-11T00:59:59-05:00"

      122 |     const d = dayjs.tz(s, NY)
      123 |     const m = moment.tz(s, NY)
    > 124 |     expect(d.format()).toBe('2012-03-11T01:59:59-05:00')
      125 |     expect(d.format()).toBe(m.format())
      126 |     expect(d.utcOffset()).toBe(-300)
      127 |     expect(d.utcOffset()).toBe(m.utcOffset())

      at Object.<anonymous> (test/plugin/timezone.test.js:124:24)

  ● 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-11T02:00:00-04:00"

      133 |     const d = dayjs.tz(s, NY)
      134 |     const m = moment.tz(s, NY)
    > 135 |     expect(d.format()).toBe('2012-03-11T03:00:00-04:00')
      136 |     expect(d.format()).toBe(m.format())
      137 |     expect(d.valueOf()).toBe(m.valueOf())
      138 |     expect(d.valueOf()).toBe(1331449200000)

      at Object.<anonymous> (test/plugin/timezone.test.js:135: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-11T02:59:59-04:00"

      144 |     const d = dayjs.tz(s, NY)
      145 |     const m = moment.tz(s, NY)
    > 146 |     expect(d.format()).toBe('2012-03-11T03:59:59-04:00')
      147 |     expect(d.format()).toBe(m.format())
      148 |     expect(d.valueOf()).toBe(m.valueOf())
      149 |     expect(d.valueOf()).toBe(1331452799000)

      at Object.<anonymous> (test/plugin/timezone.test.js:146: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-11T02:00:00-04:00"

      155 |     const d = dayjs.tz(s, NY)
      156 |     const m = moment.tz(s, NY)
    > 157 |     expect(d.format()).toBe('2012-03-11T03:00:00-04:00')
      158 |     expect(d.format()).toBe(m.format())
      159 |     expect(d.valueOf()).toBe(m.valueOf())
      160 |     expect(d.valueOf()).toBe(1331449200000)

      at Object.<anonymous> (test/plugin/timezone.test.js:157:24)

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

    expect(received).toBe(expected) // Object.is equality

    Expected value to be:
      "2012-11-04T00:59:59-04:00"
    Received:
      "2012-11-03T23:59:59-04:00"

      171 |     [dayjs, moment].forEach((_) => {
      172 |       const d = _.tz(s, NY)
    > 173 |       expect(d.format()).toBe('2012-11-04T00:59:59-04:00')
      174 |       expect(d.utcOffset()).toBe(-240)
      175 |       expect(d.valueOf()).toBe(1352005199000)
      176 |     })

      at forEach (test/plugin/timezone.test.js:173:26)
          at Array.forEach (<anonymous>)
      at Object.<anonymous> (test/plugin/timezone.test.js:171:21)

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

    expect(received).toBe(expected) // Object.is equality

    Expected value to be:
      "2012-11-04T01:00:00-04:00"
    Received:
      "2012-11-04T00:00:00-04:00"

      180 |     [dayjs, moment].forEach((_) => {
      181 |       const d = _.tz(s, NY)
    > 182 |       expect(d.format()).toBe('2012-11-04T01:00:00-04:00')
      183 |       expect(d.utcOffset()).toBe(-240)
      184 |       expect(d.valueOf()).toBe(1352005200000)
      185 |     })

      at forEach (test/plugin/timezone.test.js:182:26)
          at Array.forEach (<anonymous>)
      at Object.<anonymous> (test/plugin/timezone.test.js:180:21)

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

    expect(received).toBe(expected) // Object.is equality

    Expected value to be:
      "2012-11-04T01:59:59-04:00"
    Received:
      "2012-11-04T00:59:59-04:00"

      189 |     [dayjs, moment].forEach((_) => {
      190 |       const d = _.tz(s, NY)
    > 191 |       expect(d.format()).toBe('2012-11-04T01:59:59-04:00')
      192 |       expect(d.utcOffset()).toBe(-240)
      193 |       expect(d.valueOf()).toBe(1352008799000)
      194 |     })

      at forEach (test/plugin/timezone.test.js:191:26)
          at Array.forEach (<anonymous>)
      at Object.<anonymous> (test/plugin/timezone.test.js:189:21)

  ● 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"

      198 |     [dayjs, moment].forEach((_) => {
      199 |       const d = _.tz(s, NY)
    > 200 |       expect(d.format()).toBe('2012-11-04T02:00:00-05:00')
      201 |       expect(d.utcOffset()).toBe(-300)
      202 |       expect(d.valueOf()).toBe(1352012400000)
      203 |     })

      at forEach (test/plugin/timezone.test.js:200:26)
          at Array.forEach (<anonymous>)
      at Object.<anonymous> (test/plugin/timezone.test.js:198:21)

Test Suites: 3 failed, 54 passed, 57 total
Tests:       11 failed, 541 passed, 552 total
Snapshots:   0 total
Time:        2.306s
Ran all test suites.
npm ERR! Test failed.  See above for more details.
iamkun commented 4 years ago

Hi, I'm not sure what caused this wired error.

I did not reproduce this error even if I changed my local timezone to "Europe/Berlin".

There's one thing I could confirm is the test runs fine in my local timezone UTC+8 and the Travis CI unit test machine UTC 0.

avendiart commented 4 years ago

@iamkun have you tried running it with the specified configuration within the container?

iamkun commented 4 years ago

I don't know docker much.

I've only updated my system timezone in "System preferences".

avendiart commented 4 years ago

Can you set the Travis CI to a different Timezone? Something like UTC+2 and check if tests still pass?

iamkun commented 4 years ago

We've already did this https://github.com/iamkun/dayjs/blob/dev/package.json#L9

But I will try UTC+2 later.

avendiart commented 4 years ago

I'm not 100% sure, but I don't think that actually changes the timezone of the system. I'd try setting it like:

before_install:
- export TZ=Europe/Berlin

or trying to run tests using the specified container. Moment and Luxon seem to respect the system timezone correctly, while I had no luck with dayjs. Incidentally it works fine if system timezone is UTC, but I think it's indeed rather a coincidence than the desired behaviour.

iamkun commented 4 years ago

This should work will.

image

iamkun commented 3 years ago

I'll close this issue since it's been a while since it's been opened. Feel free to reopen if you have updates on this

Bessonov commented 3 years ago

@iamkun did you tried the repro above?

iamkun commented 3 years ago

Yes, but everything seems all right

Bessonov commented 3 years ago

Well, I get following result:

Summary of all failing tests
 FAIL  test/plugin/timezone.test.js (6.961s)
  ● 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)

Test Suites: 1 failed, 64 passed, 65 total
Tests:       5 failed, 597 passed, 602 total

with current master.

iamkun commented 3 years ago

@Bessonov Yes, finally I can reproduce it after changing the macOS system's timezone. This might be a bug.

antoninmorvan commented 3 years ago

I don't know if it's linked by this bug, but i encountered a problem when i try to setup timezone with jest tests :

On jest.setup.js :

dayjs.tz.setDefault('Europe/Paris'); And when i log dayjs.tz.guess() on tests, i have following error :

TypeError: Intl.DateTimeFormat(...).resolvedOptions is not a function

jest test are launched with NODE_ICU_DATA=node_modules/full-icu jest command in package.json

amberfrontend commented 3 years ago

I'm also running into something similar. My tests pass locally, but not in CI. There is a -7:00 timezone difference between the expected and the actual.

Screen Shot 2021-05-12 at 12 41 28 PM
amberfrontend commented 3 years ago

@antoninmorvan Did you import the plugins for utc and timezone?

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

dayjs.extend(utc)
dayjs.extend(timezone)
dayjs.tz.setDefault('Europe/Paris')
Tulkdan commented 2 years ago

Hi, @amberfrontend I'm getting the same trouble when testing in docker, I tried your idea and I got in these topic of the documentation https://day.js.org/docs/en/parse/utc

// default local time
dayjs().format() //2019-03-06T08:00:00+08:00

It looks like that using dayjs() will always use the local time instead of the timezone that we set up when testing. So probably this is a bug in the library and I still haven't figured it out how we can use it. Maybe we can always use the dayjs.utc() to always get the UTC time, but I need to check it out if it will work.

UPDATE: I got it working with mocha+sinon to fake the time on the tests, you can still use the timezone the you set it up and make sinon to use a fake time with the timezone configured like this:

const fakeDate = dayjs.tz('2021-11-23').toDate();
const datetime = sinon.useFakeTimers(fakeDate);

This should probably force the timezone in the test that you're running, so if you use dayjs() in your code/component it should also use the timezone.