hexo
hexo copied to clipboard
Date & Timezone issue related with Front-Matter
Check List
Please check the following before submitting a new issue.
- [x] I have already read Docs page & Troubleshooting page
- [x] I have already searched existing issues and they are not helpful to me
- [x] I examined error or warning messages and it's difficult to solve
- [x] Using the latest version of Hexo (run
hexo version
to check) - [x] Node.js is higher than minimum required version
The issue has been reported in
- #4239
- #3397
- #3282
- #2063
For example, I have a post setup as following:
# _config.yml
timezone: Asia/Shanghai
title: Hello World
date: 2020-09-29 23:00:00
Also, my machine is under the Asia/Shanghai
timezone, which will also affect Node.js' timezone.
After the front-matter being processed by js-yaml
, the "Date-like string" will be converted into Date
object:
const jsYaml = require("js-yaml");
jsYaml.load('date: 2020-09-29 23:00:00');
// > "Tue, 29 Sep 2020 23:00:00 GMT"
Notice that the input was converted into the UTC? Users will only fill in the front-matter with their local time, not the UTC. Thus it is not the desired behavior.
So during the processing of front-matter, Date#getTimezoneOffset
has been used:
// https://github.com/hexojs/hexo-front-matter/blob/ccbdff36d151a56932418cdc6d0329d866032a1b/lib/front_matter.js#L55-L62
// Convert timezone
Object.keys(data).forEach(key => {
const item = data[key];
if (item instanceof Date) {
data[key] = new Date(item.getTime() + (item.getTimezoneOffset() * 60 * 1000));
}
});
It will result in:
"Tue, 29 Sep 2020 15:00:00 GMT"
Which is the desired behavior.
Then, during the processing pf posts, moment.timezone
was used:
https://github.com/hexojs/hexo/blob/557487a2f8ab0065bf94d5a9466c54034f1db17f/lib/plugins/processor/post.js#L80-L82 https://github.com/hexojs/hexo/blob/557487a2f8ab0065bf94d5a9466c54034f1db17f/lib/plugins/processor/common.js#L51-L60
If the config.timezone
is configured correctly, there will be no differences between before and after timezone()
:
"Tue, 29 Sep 2020 15:00:00 GMT"
// There's no differences
A demo can be found here: https://runkit.com/sukkaw/5f732261a7aac8001a42bcc4
Date#getTimezoneOffset: -480
Date parsed by js-yaml: Tue, 29 Sep 2020 23:00:00 GMT
Date after calculating the timezone offset: Tue, 29 Sep 2020 15:00:00 GMT
Date after moment-timezone: Tue, 29 Sep 2020 15:00:00 GMT
Date after moment-timezone (without pre offset): Tue, 29 Sep 2020 15:00:00 GMT // Will be discussed later
So, what about a different timezone environment? For example, the CI environment. Its timezone will not be Asia/Shanghai
.
So here is another demo: https://repl.it/repls/LividBewitchedControlflowgraph#index.js
Date#getTimezoneOffset: 0 // See? It is not -480 anymore, it is now 0
Date parsed by js-yaml: Tue, 29 Sep 2020 23:00:00 GMT
Date after calculating the timezone offset: Tue, 29 Sep 2020 23:00:00 GMT // It is now wrong
Date after moment-timezone: Tue, 29 Sep 2020 15:00:00 GMT // But it is still correct
Date after moment-timezone (without pre offset): Tue, 29 Sep 2020 15:00:00 GMT // Will be discussed later
As you can see, Date after calculating the timezone offset
is now wrong, while Date after moment-timezone
is still correct. That's because timezone()
takes getTimezoneOffset
into consideration.
So, what about removing "getTimezoneOffset" completely?
Here goes Date after moment-timezone (without pre offset)
. It is generated without using Date#getTimezoneOffset
, and the result is still correct. It also means it is not affected by the environment (no `Date#getTimezoneOffset being used).
By eliminating the Node.js timezone affection (only dependents on users' config.timezone
configuration) the timezone issue should be solved.
cc @YoshinoriN @ItsZero @stevenjoezhang @curbengh
So far I just assume those issues were caused by their machines' timezones are inconsistent with their hexo configurations.
So, what about removing "getTimezoneOffset" completely?
+1, Hexo shouldn't need to query the host machine's timezone, config.timezone
should be the canonical timezone.
There is still a need to query host's timezone since config.timezone
is empty by default. Host's timezone should be ignored if config.timezone
is specified.
Another complication is that it is also possible to specify timezone in front-matter, e.g. 2013-02-08 09:30:26.123+07:00
.
Perhaps we can prioritise like this:
- Front-matter's timezone
- config.timezone
- host's timezone
There is still a need to query the host's timezone
@curbengh
It appears that there is no way we could get the timezone name directly (If so, we could use it as a default value during hexo config processing). The only thing we get is getTimezoneOffset
.
@curbengh
We can use JavaScript built-in object Intl
:
Intl.DateTimeFormat().resolvedOptions().timeZone
// UTC
// Asia/Tokyo
// etc.
We can use it for the default timezone in config.