iamkun / iamkun/dayjs

UTC time convert error (and temporary solving method)

Open
#2,303 3 comments 8 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
48.7k
Forks
2.5k
PR merge metrics
No merged PRs in 30d

Description

**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'
```js
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:
```js
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
```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**
```js
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);
}
```

Contributor guide

Open the contributing guide

Research direction

Start in src/plugin/timezone/index.js, especially the proto.tz conversion and its use of toLocaleString and new Date(target). Reproduce the reported Australia/Adelaide and Asia/Shanghai conversions, then verify that the resulting offsets remain correct across the daylight-saving transition described in the issue.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.