hexo
hexo copied to clipboard
permalink date is incorrect if the time zone of _config.yml and the time zone setting of the machine are different
Environment Info
Node version(node -v
):v10.9.0
site to reproduce the ploblem:
https://github.com/MatchaChoco010/hexo-timezone-permalink
$ hexo version
hexo: 3.7.1
hexo-cli: 1.1.0
os: Linux 4.4.0-17134-Microsoft linux x64
http_parser: 2.8.0
node: 10.9.0
v8: 6.8.275.24-node.14
uv: 1.22.0
zlib: 1.2.11
ares: 1.14.0
modules: 64
nghttp2: 1.32.0
napi: 3
openssl: 1.1.0i
icu: 62.1
unicode: 11.0
cldr: 33.1
tz: 2018e
For BUG
_config.yml is this:
...
timezone: America/New_York
...
permalink: :year/:month/:day/:title/
...
and source/_posts/test.md
is this:
---
title: test
date: 2018-10-11 23:00:00
tags:
---
The permalink of this article should be /2018/10/11/test/
.
But hexo generate
in Japan, which +0900, /2018/10/12/test/index.html
is generated.
The article date is correct (2018/10/11).
Change the machine timezone to -0500 and hexo generate
, /2018/10/11/test.index.html
is generated.
It seems that the permalink is not generated correctly if the time zone of _config.yml and the time zone setting of the machine are incorrect.
@MatchaChoco010 Thanks a report. I reproduced it. But, I can't judge fix this behavior or not. I think this problem impact is big.
I ask to other hexo maintainer this problem.
@tommy351 @NoahDragon @JLHwung How do you think about this.
I spent some time digging into this today and found out where the bug is. Unfortunately removing timezone
from _config.yml is not a valid workaround me because I run the build on a cloud server just prior to deploy which is running in UTC timezone.
Why the timezone is off?
In plugins/filter/post_permalink.js
we can see how the path is constructed. It reads from data.date
which is prepared by the hexo database layer. If you print the value, you will see that while the timestamp is correct, its timezone is off -- It's just UTC.
Why is the timezone specified in _config.yml not applied?
Next, I dig into why the timezone specified in the config file was not applied. The timezone is being used in models/types/moment.js
in the cast
function: It reads options.timezone
where it is defined in models/post.js
by reading [ctx.config.timezone](https://github.com/hexojs/hexo/blob/master/lib/models/post.js#L25)
.
Why the config appeared as the default config?
Now if you print out ctx.config
, you will see that it is NOT your personal config. Instead, it's the default config comes with hexo. Digging into how hexo initialize hexo/index.js
, we see that [registerModels](https://github.com/hexojs/hexo/blob/master/lib/hexo/index.js#L100)
happened before [load_config](https://github.com/hexojs/hexo/blob/master/lib/hexo/index.js#L169)
. That's why!
Now, how to fix this?
This is where I'm not sure what's the best way to proceed. I think the current logic is wrong. We obviously are using config before it is loaded. We have a few options here:
- Move the initialization until after we load the config (aka here): This makes the most sense to me, however, it breaks tests because some of them don't call
hexo.init()
before using hexo stuff. I'm not sure how big the assumptions were.hexo.init()
is also, unfortunately, an async function so we can't just simply call it in those callsites too. - Make load_config synchronous and load it before init: It's a safer way to fix this as it maintains the API interface. However, now we will be reading config file before
init()
is being called which might break some other cases as well. It also makes theinit
function useless.
I'm happy to code this up and send a PR, but I would like to discuss which approach would be more preferable?
Thanks!
still have someone try to fix this?
@tobyqin So far, it is still remain as a known issue.
@SukkaW thanks, I workaround it by removing the timezone info in config file and build environment.