Open irgipaulius opened 1 year ago
My timezone is Europe/Vilnius.
This is curious. running with moment ^2.29.3 I get a different result. I don't know how to make such cool demos, so I'll just put it here:
code:
const moment = require("moment");
const dayjs = require("dayjs");
const utc = require("dayjs/plugin/utc");
dayjs.extend(utc);
const f = "YYYY-MM-DD HH:mm:ss Z";
// loop same day every 11 years for the past 200 years
for (let i = 2022; i > 1800; i -= 11) {
const dayjsDate = dayjs(`12/31/${i}`).utc(true).format(f);
const momentDate = moment.utc(`12/31/${i}`).format(f).toString();
console.log(`${dayjsDate} === ${momentDate}`);
}
result:
2022-12-31 00:00:00 +00:00 === 2022-12-31 00:00:00 +00:00
2011-12-31 00:00:00 +00:00 === 2011-12-31 00:00:00 +00:00
2000-12-31 00:00:00 +00:00 === 2000-12-31 00:00:00 +00:00
1989-12-31 00:00:00 +00:00 === 1989-12-31 00:00:00 +00:00
1978-12-31 00:00:00 +00:00 === 1978-12-31 00:00:00 +00:00
1967-12-31 00:00:00 +00:00 === 1967-12-31 00:00:00 +00:00
1956-12-31 00:00:00 +00:00 === 1956-12-31 00:00:00 +00:00
1945-12-31 00:00:00 +00:00 === 1945-12-31 00:00:00 +00:00
1934-12-31 00:00:00 +00:00 === 1934-12-31 00:00:00 +00:00
1923-12-31 00:00:00 +00:00 === 1923-12-31 00:00:00 +00:00
1912-12-31 00:06:00 +00:00 === 1912-12-31 00:00:00 +00:00
1901-12-31 00:06:00 +00:00 === 1901-12-31 00:00:00 +00:00
1890-12-31 00:06:00 +00:00 === 1890-12-31 00:00:00 +00:00
1879-12-31 00:03:44 +00:00 === 1879-12-31 00:00:00 +00:00
1868-12-31 00:03:44 +00:00 === 1868-12-31 00:00:00 +00:00
1857-12-31 00:03:44 +00:00 === 1857-12-31 00:00:00 +00:00
1846-12-31 00:03:44 +00:00 === 1846-12-31 00:00:00 +00:00
1835-12-31 00:03:44 +00:00 === 1835-12-31 00:00:00 +00:00
1824-12-31 00:03:44 +00:00 === 1824-12-31 00:00:00 +00:00
1813-12-31 00:03:44 +00:00 === 1813-12-31 00:00:00 +00:00
1802-12-31 00:03:44 +00:00 === 1802-12-31 00:00:00 +00:00
the results differ very much depending on the location of the machine. Shouldn't utc
be idempotent?
Edit: formatted the output
Indeed, depends on localtion, but I'm getting the same result for both libs, again small demo and my results:
2022-12-31 00:00:00 +00:00 === 2022-12-31 00:00:00 +00:00
2011-12-31 00:00:00 +00:00 === 2011-12-31 00:00:00 +00:00
2000-12-31 00:00:00 +00:00 === 2000-12-31 00:00:00 +00:00
1989-12-31 00:00:00 +00:00 === 1989-12-31 00:00:00 +00:00
1978-12-31 00:00:00 +00:00 === 1978-12-31 00:00:00 +00:00
1967-12-31 00:00:00 +00:00 === 1967-12-31 00:00:00 +00:00
1956-12-31 00:00:00 +00:00 === 1956-12-31 00:00:00 +00:00
1945-12-31 00:00:00 +00:00 === 1945-12-31 00:00:00 +00:00
1934-12-31 00:00:00 +00:00 === 1934-12-31 00:00:00 +00:00
1923-12-31 00:00:00 +00:00 === 1923-12-31 00:00:00 +00:00
1912-12-30 23:59:43 +00:00 === 1912-12-30 23:59:43 +00:00
1901-12-30 23:59:43 +00:00 === 1901-12-30 23:59:43 +00:00
1890-12-30 23:59:43 +00:00 === 1890-12-30 23:59:43 +00:00
1879-12-30 23:59:43 +00:00 === 1879-12-30 23:59:43 +00:00
1868-12-30 23:59:43 +00:00 === 1868-12-30 23:59:43 +00:00
1857-12-30 23:59:43 +00:00 === 1857-12-30 23:59:43 +00:00
1846-12-30 23:59:43 +00:00 === 1846-12-30 23:59:43 +00:00
1835-12-30 23:59:43 +00:00 === 1835-12-30 23:59:43 +00:00
1824-12-30 23:59:43 +00:00 === 1824-12-30 23:59:43 +00:00
1813-12-30 23:59:43 +00:00 === 1813-12-30 23:59:43 +00:00
1802-12-30 23:59:43 +00:00 === 1802-12-30 23:59:43 +00:00
Seems to be a bug with utc
function. With utcOffset
the result is correct:
dayjs(
12/31/${i}).utcOffset(0,true).format("YYYY-MM-DD HH:mm:ss:SSS Z")
This is not a bug, but the correct implementation of time zones. So for example for CET the definition of the time zone ("UTC offset") changed several times over the years, as can be seen in the timeanddate web page).
The time zone definitions can be found on the iana Time Zone Database. This database is implemented for example in the Internationalization API of javascript, the basis for time zones in dayjs.
@BePo65 interesting. This causes a few issues for my needs though.
are there any other ways to set utc mode without this "feature"?
currently I use moment and it works as I expect it to.
This is not a bug, but the correct implementation of time zones. So for example for CET the definition of the time zone ("UTC offset") changed several times over the years, as can be seen in the timeanddate web page).
The time zone definitions can be found on the iana Time Zone Database. This database is implemented for example in the Internationalization API of javascript, the basis for time zones in dayjs.
Hi, sorry, I'm far from timezones, but why does .utcOffset(0,true)
has another results?
why does .utcOffset(0,true) has another results
Using utcOffset
with 1 parameter, sets the utcOffset of a given dayjs object.
Using utcOffset
with 2 parameters, sets the utcOffset of a given dayjs object while keeping the time value of that object. And therefore using .utcOffset(0, true) gets other values (this fragment avoids the critical branch in the code).
Regarding that point, the documentation is not really complete (at least I didn't find it in the documentation, only in the source code). @Bykiev : perhaps you want to make a PR for the documentation on the corresponding project?
Back to time zones / utcOffset:
sorry that it took me so long to understand the issue. If I get it right, your point is not about correct definition of timezones. The point is that .utcOffset(true) does not keep the local time. And that is really an error in dayjs.
I'm working on a pr for this issue; give me a few days.
in the meantime: how about using
dayjs.utc(`12/31/${i}`).format(f)
instead of
dayjs(`12/31/${i}`).utc(true).format(f)
In a quick test, this solves the point on my machine (I believe 😄 ).
Nevertheless I will try to fix the utcOffset issue, as I am working on the dayjs 2.0 utc plugin and this could / should be fixed there too.
why does .utcOffset(0,true) has another results
Using
utcOffset
with 1 parameter, sets the utcOffset of a given dayjs object.Using
utcOffset
with 2 parameters, sets the utcOffset of a given dayjs object while keeping the time value of that object. And therefore using .utcOffset(0, true) gets other values (this fragment avoids the critical branch in the code).Regarding that point, the documentation is not really complete (at least I didn't find it in the documentation, only in the source code). @Bykiev : perhaps you want to make a PR for the documentation on the corresponding project?
Back to time zones / utcOffset: sorry that it took me so long to understand the issue. If I get it right, your point is not about correct definition of timezones. The point is that .utcOffset(true) does not keep the local time. And that is really an error in dayjs.
I'm working on a pr for this issue; give me a few days.
Thank you for your investigation, indeed, utcOffset(true)
doesn't preserve time, but it's undocumented feature and should be avoided.
I can't understand, why does time converted from 1912-12-30
to 1912-12-30 23:59:43 +00:00
while using utc(true)
and converted to 1912-12-31 00:00:0 +00:00
while using utcOffset(0,true)
? My timezone is Europe/Moscow
in console:
$y: 1912…}
$L: "en"
$u: true
$d: Tue Dec 31 1912 02:30:00 GMT+0230 (Москва, стандартное время)
$x: Object
$y: 1912
$M: 11
$D: 30
$W: 1
$H: 23
$m: 59
$s: 43
$ms: 0
in the meantime: how about using
dayjs.utc(`12/31/${i}`).format(f)
instead of
dayjs(`12/31/${i}`).utc(true).format(f)
In a quick test, this solves the point on my machine (I believe 😄 ).
Nevertheless I will try to fix the utcOffset issue, as I am working on the dayjs 2.0 utc plugin and this could / should be fixed there too.
With such format it returns the same 1912-12-30 23:59:43 +00:00
, but if the input string format is RFC2822/ISO (${i}-12-31
) it'll return 1912-12-31 00:00:0 +00:00
.
I did some more research and it seems the issue is not related to dayjs, here is small demo with date:
Ouput:
Sat Dec 31 2022 03:00:00 GMT+0300 (Москва, стандартное время)
Sat Dec 31 2011 04:00:00 GMT+0400 (Москва, стандартное время)
Sun Dec 31 2000 03:00:00 GMT+0300 (Москва, стандартное время)
Sun Dec 31 1989 03:00:00 GMT+0300 (Москва, стандартное время)
Sun Dec 31 1978 03:00:00 GMT+0300 (Москва, стандартное время)
Sun Dec 31 1967 03:00:00 GMT+0300 (Москва, стандартное время)
Mon Dec 31 1956 03:00:00 GMT+0300 (Москва, стандартное время)
Mon Dec 31 1945 03:00:00 GMT+0300 (Москва, стандартное время)
Mon Dec 31 1934 03:00:00 GMT+0300 (Москва, стандартное время)
Mon Dec 31 1923 02:00:00 GMT+0200 (Москва, стандартное время)
Tue Dec 31 1912 02:30:17 GMT+0230 (Москва, стандартное время)
Tue Dec 31 1901 02:30:17 GMT+0230 (Москва, стандартное время)
Wed Dec 31 1890 02:30:17 GMT+0230 (Москва, стандартное время)
Wed Dec 31 1879 02:30:17 GMT+0230 (Москва, стандартное время)
Thu Dec 31 1868 02:30:17 GMT+0230 (Москва, стандартное время)
Thu Dec 31 1857 02:30:17 GMT+0230 (Москва, стандартное время)
Thu Dec 31 1846 02:30:17 GMT+0230 (Москва, стандартное время)
Thu Dec 31 1835 02:30:17 GMT+0230 (Москва, стандартное время)
Fri Dec 31 1824 02:30:17 GMT+0230 (Москва, стандартное время)
Fri Dec 31 1813 02:30:17 GMT+0230 (Москва, стандартное время)
Fri Dec 31 1802 02:30:17 GMT+0230 (Москва, стандартное время)
Still can't understand how did it working as UTC offset in 1912 is +02:30... Where 17 seconds are from?
@BePo65, thank you for your links above, all is correct, the timezone shift in 1912 was +02:30:17
My misunderstood between utc(true)
and utcOffset(0, true)
is utc(true)
converting time from timezone to UTC, but utcOffset(0, true)
just preserve specified time with specified time shift.
One of the problems of offset is the handling of seconds (see issue #1905).
After more tests and investigation here my current interpretation of the original problem of this issue:
The code from @irgipaulius compares dayjs'12/31/2000').utc(true).format(f)
with moment.utc('12/31/2000').format(f)
and gets different results for the 2 values; which is ok, because
.utc(true)
takes the original date (2000-12-31T00:00:00.000
) and converts it to an utc date keeping the local time resulting in 2000-12-31T00:00:00.000
..utc('12/31/2000')
simply parses the string and creates an utc date from it (2000-12-31T00:00:00.000
)..Both results look the same at the first view, but things get complicated, if the timezone offset contains seconds. Using utc(dateString)
simply ignores the offset, as it parses directly to an utc date, while date(datestring).utc(true)
subtracts the utcOffset (which includes the seconds) from the date (which does not contain the seconds). As a result the time part gets "wrong". And that's true for moment and dayjs.
I created an example for 'Europe/Kiev": | element | value | comment |
---|---|---|---|
dateString | '1879-12-31' | ||
utcOffset | 122 | to be exactly: "02:02:04" | |
date.utc().format(f) | "1879-12-30 21:57:56 +00:00" | .utc() just ignores the time | |
date.utc(true).format(f) | "1879-12-30 23:59:56 +00:00" | here are the 4s from the exact utcOffset | |
dayjs.utc(dateString).format(f) | "1879-12-31 00:00:00 +00:00" | parses the string directly to utc |
So if you would use the same function for moment and dayjs, the results would be s´the same in both cases - even moment(string).utc(true) shows the 'mysterious' seconds 😄
Besides of this, there remains the problem of dayjs with seconds in the timezone offset (see also issue #1905). I created a PR (#2016) for this, hoping that it helps solve the points with historical dates.
Describe the bug Take this as an example:
Expected behavior
Actual behavior
Information