Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lib/hexo/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,9 @@ class Post {
return readFile(src);
}).then(content => {
// Create post
Object.assign(data, yfmParse(content));
Object.assign(data, yfmParse(content, {
defaultTimeZone: config.timezone
}));
data.content = data._content;
data._content = undefined;

Expand Down
16 changes: 12 additions & 4 deletions lib/models/types/moment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,18 @@ class SchemaTypeMoment extends warehouse.SchemaType<moment.Moment> {
}

function toMoment(value) {
// FIXME: Something is wrong when using a moment instance. I try to get the
// original date object and create a new moment object again.
if (moment.isMoment(value)) return moment((value as any)._d);
return moment(value);
// value passed here is a moment-like instance
// but it's a plain object that methods such as isValid are removed
// moment.isMoment is judged on its property but not constructor
// so the plain object still passes the moment.isMoment check

// hexo-front-matter now always returns date in UTC
// See https://github.com/hexojs/hexo-front-matter/pull/146
// We shall specify the timezone UTC here
// Otherwise, `moment()` set the timezone according to the $TZ on the machine
// Which still cause confusion
if (moment.isMoment(value)) return moment((value as any)._d).tz('UTC');
return moment(value).tz('UTC');
}

export = SchemaTypeMoment;
4 changes: 3 additions & 1 deletion lib/plugins/processor/asset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ function processPage(ctx: Hexo, file: _File) {
file.stat(),
file.read()
]).spread((stats: Stats, content: string) => {
const data: PageSchema = yfm(content);
const data: PageSchema = yfm(content, {
defaultTimeZone: config.timezone
});
const output = ctx.render.getOutput(path);

data.source = path;
Expand Down
15 changes: 12 additions & 3 deletions lib/plugins/processor/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,21 @@ export {isTmpFile};
export {isHiddenFile};
export {isExcludedFile};

// This function is used by `asset.ts` and `post.ts`
// To handle dates like `date: Apr 24 2014` in front-matter
export function toDate(date?: string | number | Date | moment.Moment): Date | undefined | moment.Moment {
if (!date || moment.isMoment(date)) return date as any;

if (!(date instanceof Date)) {
// hexo-front-matter now always returns date in UTC
// but `new Date()` uses local timezone by default
// We have to reset offset
// to make the behavior consistent with hexo-front-matter
date = new Date(date);
const ms = date.getTime();
const offset = date.getTimezoneOffset();
const diff = offset * DURATION_MINUTE;
date = new Date(ms - diff);
}

if (isNaN(date.getTime())) return;
Expand All @@ -43,12 +53,11 @@ export function toDate(date?: string | number | Date | moment.Moment): Date | un
export function adjustDateForTimezone(date: Date | moment.Moment, timezone: string) {
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;
const diff = target * DURATION_MINUTE;

return new Date(ms - diff);
return new Date(ms + diff);
}

export {isMatch};
14 changes: 11 additions & 3 deletions lib/plugins/processor/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ function processPost(ctx: Hexo, file: _File) {
file.stat(),
file.read()
]).spread((stats: Stats, content: string) => {
const data: PostSchema = yfm(content);
const data: PostSchema = yfm(content, {
defaultTimeZone: config.timezone
});
const info = parseFilename(config.new_post_name, path);
const keys = Object.keys(info);

Expand All @@ -119,15 +121,21 @@ function processPost(ctx: Hexo, file: _File) {
}

if (data.date) {
// hexo-front-matter now always returns date in UTC
// See https://github.com/hexojs/hexo-front-matter/pull/146
data.date = toDate(data.date) as any;
} else if (info && info.year && (info.month || info.i_month) && (info.day || info.i_day)) {
data.date = new Date(
// Date parsed from permalink should also use UTC
// to make the behavior consistent with hexo-front-matter
// It will be corrected by invoking adjustDateForTimezone later
data.date = new Date(Date.UTC(
info.year,
parseInt(info.month || info.i_month, 10) - 1,
parseInt(info.day || info.i_day, 10)
) as any;
)) as any;
}

// Convert date and updated time from UTC to local time (based on timezone in Hexo config)
if (data.date) {
if (timezone) data.date = adjustDateForTimezone(data.date, timezone) as any;
} else {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"fast-archy": "^1.0.0",
"fast-text-table": "^1.0.1",
"hexo-cli": "^4.3.2",
"hexo-front-matter": "^4.2.1",
"hexo-front-matter": "^5.0.0",
"hexo-fs": "^5.0.0",
"hexo-i18n": "^2.0.0",
"hexo-log": "^4.1.0",
Expand Down
2 changes: 1 addition & 1 deletion test/scripts/console/new.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ describe('new', () => {
const date = moment(now);
const path = join(hexo.source_dir, '_posts', 'Hello-World.md');
const body = [
'title: \'\'\'Hello\'\' World\'',
'title: "\'Hello\' World"',
'foo: bar',
'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
'tags:',
Expand Down
29 changes: 12 additions & 17 deletions test/scripts/filters/post_permalink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('post_permalink', () => {
const apost = await Post.insert({
source: 'foo.md',
slug: 'foo',
date: moment('2014-01-02')
date: moment.utc('2014-01-02')
});
const id = apost._id;
await apost.setCategories(['foo', 'bar']);
Expand Down Expand Up @@ -77,7 +77,7 @@ describe('post_permalink', () => {
source: 'sub/2015-05-06-my-new-post.md',
slug: '2015-05-06-my-new-post',
title: 'My New Post',
date: moment('2015-05-06')
date: moment.utc('2015-05-06')
});
postPermalink(post).should.eql('2015/05/06/my-new-post/');
Post.removeById(post._id);
Expand All @@ -90,7 +90,7 @@ describe('post_permalink', () => {
source: 'sub/2015-05-06-my-new-post.md',
slug: '2015-05-06-my-new-post',
title: 'My New Post',
date: moment('2015-05-06 12:13:14')
date: moment.utc('2015-05-06 12:13:14')
});
postPermalink(post).should.eql('2015/05/06/12/13/14/my-new-post/');
Post.removeById(post._id);
Expand All @@ -100,8 +100,8 @@ describe('post_permalink', () => {
hexo.config.permalink = ':timestamp/:slug';
const timestamp = '1736401514';
const dates = [
moment('2025-01-09 05:45:14Z'),
moment('2025-01-08 22:45:14-07')
moment.utc('2025-01-09 05:45:14Z'),
moment.utc('2025-01-08 22:45:14-07')
];
const posts = await Post.insert(
dates.map((date, idx) => {
Expand All @@ -126,7 +126,7 @@ describe('post_permalink', () => {
source: 'sub/2015-05-06-my-new-post.md',
slug: '2015-05-06-my-new-post',
title: 'My New Post',
date: moment('2015-05-06')
date: moment.utc('2015-05-06')
});
postPermalink(post).should.eql('2015/05/06/00/00/00/my-new-post/');
Post.removeById(post._id);
Expand Down Expand Up @@ -180,14 +180,12 @@ describe('post_permalink', () => {
source: 'my-new-post.md',
slug: 'hexo/permalink-test',
__permalink: 'hexo/permalink-test',
title: 'Permalink Test',
date: moment('2014-01-02')
title: 'Permalink Test'
}, {
source: 'another-new-post.md',
slug: '/hexo-hexo/permalink-test-2',
__permalink: '/hexo-hexo/permalink-test-2',
title: 'Permalink Test',
date: moment('2014-01-02')
title: 'Permalink Test'
}]);

postPermalink(posts[0]).should.eql('/hexo/permalink-test');
Expand All @@ -203,7 +201,7 @@ describe('post_permalink', () => {
const post = await Post.insert({
source: 'foo.md',
slug: 'foo',
date: moment('2014-01-02')
date: moment.utc('2014-01-02')
});

postPermalink(post).should.eql('2014/01/02/foo/');
Expand All @@ -220,20 +218,17 @@ describe('post_permalink', () => {
source: 'my-new-post.md',
slug: 'hexo/permalink-test',
__permalink: 'hexo/permalink-test',
title: 'Permalink Test',
date: moment('2014-01-02')
title: 'Permalink Test'
}, {
source: 'another-new-post.md',
slug: '/hexo-hexo/permalink-test-2',
__permalink: '/hexo-hexo/permalink-test-2/',
title: 'Permalink Test',
date: moment('2014-01-02')
title: 'Permalink Test'
}, {
source: 'another-another-new-post.md',
slug: '/hexo-hexo/permalink-test-3',
__permalink: '/hexo-hexo/permalink-test-3.html',
title: 'Permalink Test',
date: moment('2014-01-02')
title: 'Permalink Test'
}]);

postPermalink(posts[0]).should.eql('/hexo/permalink-test/');
Expand Down
10 changes: 5 additions & 5 deletions test/scripts/models/moment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ describe('SchemaTypeMoment', () => {
const type = new SchemaTypeMoment('test');

it('cast()', () => {
type.cast(1e8).should.eql(moment(1e8));
type.cast(new Date(2014, 1, 1)).should.eql(moment(new Date(2014, 1, 1)));
type.cast('2014-11-03T07:45:41.237Z').should.eql(moment('2014-11-03T07:45:41.237Z'));
type.cast(moment(1e8)).valueOf().should.eql(1e8);
type.cast(1e8).should.eql(moment.utc(1e8).tz('UTC'));
type.cast(new Date(2014, 1, 1)).should.eql(moment.utc(new Date(2014, 1, 1)).tz('UTC'));
type.cast('2014-11-03T07:45:41.237Z').should.eql(moment.utc('2014-11-03T07:45:41.237Z').tz('UTC'));
type.cast(moment.utc(1e8)).valueOf().should.eql(1e8);
});

it('cast() - default', () => {
Expand Down Expand Up @@ -52,7 +52,7 @@ describe('SchemaTypeMoment', () => {
});

it('parse()', () => {
type.parse('2014-11-03T07:45:41.237Z')!.should.eql(moment('2014-11-03T07:45:41.237Z'));
type.parse('2014-11-03T07:45:41.237Z')!.should.eql(moment.utc('2014-11-03T07:45:41.237Z').tz('UTC'));
should.not.exist(type.parse());
});

Expand Down
7 changes: 4 additions & 3 deletions test/scripts/processors/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import moment from 'moment';
import { isTmpFile, isHiddenFile, toDate, adjustDateForTimezone, isMatch } from '../../../lib/plugins/processor/common';
import chai from 'chai';
const should = chai.should();
const DURATION_MINUTE = 1000 * 60;

describe('common', () => {
it('isTmpFile()', () => {
Expand All @@ -21,13 +22,13 @@ describe('common', () => {
it('toDate()', () => {
const m = moment();
const d = new Date();
const diff = d.getTimezoneOffset() * DURATION_MINUTE;

should.not.exist(toDate());
toDate(m)!.should.eql(m);
toDate(d)!.should.eql(d);
toDate(1e8)!.should.eql(new Date(1e8));
toDate('2014-04-25T01:32:21.196Z')!.should.eql(new Date('2014-04-25T01:32:21.196Z'));
toDate('Apr 24 2014')!.should.eql(new Date(2014, 3, 24));
toDate(1e8)!.should.eql(new Date(1e8 - diff));
toDate('Apr 24 2014')!.should.eql(new Date(new Date(2014, 3, 24).getTime() - diff));
should.not.exist(toDate('foo'));
});

Expand Down
Loading