-
-
Notifications
You must be signed in to change notification settings - Fork 5k
Description
Check List
Please check the following before submitting a new issue.
- I have already read Docs page & Troubleshooting page
- I have already searched existing issues and they are not helpful to me
- I examined error or warning messages and it's difficult to solve
- Using the latest version of Hexo (run
hexo versionto check) - Node.js is higher than minimum required version
The issue has been reported in
- Setting timezone in config.yml doesn't work as expected #4239
- Possible dates bug lib/plugins/processor/post.js #3397
- permalink date is incorrect if the time zone of _config.yml and the time zone setting of the machine are different #3282
- timezone的配置问题 #2063
For example, I have a post setup as following:
# _config.yml
timezone: Asia/Shanghaititle: Hello World
date: 2020-09-29 23:00:00Also, 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:
hexo/lib/plugins/processor/post.js
Lines 80 to 82 in 557487a
| if (data.date) { | |
| if (timezoneCfg) data.date = timezone(data.date, timezoneCfg); | |
| } else { |
hexo/lib/plugins/processor/common.js
Lines 51 to 60 in 557487a
| exports.timezone = (date, timezone) => { | |
| if (moment.isMoment(date)) date = date.toDate(); | |
| const offset = date.getTimezoneOffset(); | |
| const ms = date.getTime(); | |
| const target = moment.tz.zone(timezone).utcOffset(ms); | |
| const diff = (offset - target) * DURATION_MINUTE; | |
| return new Date(ms - diff); | |
| }; |
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.