dayjs icon indicating copy to clipboard operation
dayjs copied to clipboard

UTC time convert error (and temporary solving method)

Open caork opened this issue 2 years ago • 3 comments

UTC time convert cause a wrong time offset here is the problem, when I use dayjs convert a time that just in the daylight saving time converting period, it will cause the time offset equal to +(X-1):00 (X is the correct offset)

when I set my timezone to Australia/Adelaide, and convert UTC time: '2022-04-02T16:30:00Z'

let dt4 = dayjs('2022-04-02T16:30:00Z');
let testTimetz4 = dayjs.tz(dt4, 'Asia/Shanghai').format('YYYY-MM-DD HH:mm:ssZ');

output: '2022-04-03 00:30:00+07:00' but Shanghai's timeOffset always stay in +8:00

here is an another case:

let dt2 = dayjs.unix(1648917000 + 1);
let testTimetz2 = dayjs.tz(dt2, 'Australia/Adelaide').format('YYYY-MM-DD HH:mm:ssZ');

output: '2022-04-03 02:00:01+08:30' correct: '2022-04-03 02:00:01+09:30'

Information

  • Day.js Version [v1.11.7]

  • OS: Windows 10 21H2

  • Time zone: [e.g. GMT+09:30 DST (Adelaide)]

the root cause of the problem src/plugin/timezone/index.js

  proto.tz = function (timezone = defaultTimezone, keepLocalTime) {
    const oldOffset = this.utcOffset()
    const date = this.toDate()
    const target = date.toLocaleString('en-US', { timeZone: timezone }) // target within timeoffset cause wrong offset in DST converting
    const diff = Math.round((date - new Date(target)) / 1000 / 60) // New Date(target) is wrong
    let ins = d(target).$set(MS, this.$ms)
      .utcOffset((-Math.round(date.getTimezoneOffset() / 15) * 15) - diff, true)
    if (keepLocalTime) {
      const newOffset = ins.utcOffset()
      ins = ins.add(oldOffset - newOffset, MIN)
    }
    ins.$x.$timezone = timezone
    return ins
  }

Temporary Fix Method

function isTimeZoneCorrect(dayjsDate, localTimeZone) {
    let timeZones = [];
    for (let i of [-2, -1, 1, 2]) {
        // in order to judge the time, we use two groups of forward/backward time's offset 
        timeZones.push(dayjsDate.add(i, 'day').format('YYYY-MM-DD HH:mm:ss'));
    }
    timeZones = timeZones.map(function(i) {
        // only use those timeoffset info
        return dayjs.tz(i, localTimeZone).format('Z');
    });
    if ([...new Set(timeZones)].length > 2) {
        // if N > 2, it means there are wrong times surround current time, but current input time must be true
        return true;
    }

    return timeZones.includes(dayjsDate.format('Z')); // if our time offset in this group, it means correct time offset
}

function repairErrorTimeOffset(dayjsDate) {
    return dayjsDate.utcOffset(dayjsDate.utcOffset() + 60, true);
}

caork avatar May 08 '23 12:05 caork

you saved my day literally thanks!

gabamnml avatar Jul 08 '23 01:07 gabamnml

This bug needs to be addressed by the dev team. It's a pretty big deal for companies who have companies all over the world sharing data.

lemmylem avatar Jul 13 '23 16:07 lemmylem

The issue still exists on version 1.11.13

Qiming-Liu avatar Mar 12 '25 01:03 Qiming-Liu