Skip to content

Date & Timezone issue related with Front-Matter #4548

@SukkaW

Description

@SukkaW

Check List

Please check the following before submitting a new issue.

The issue has been reported in


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:

if (data.date) {
if (timezoneCfg) data.date = timezone(data.date, timezoneCfg);
} else {

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions