試しにISO8601で書いてみたら動いた

アメリカに来て、 hexo new post としてみたところ、やはり date はローカルタイムで作成されていた。

ふと思いついて、 date の部分を ISO8601 の形式で書いてみたところ、正常に読み込めた。

Hexoのソースコードを読んでみた

どういうことかと思ってソースコードを読んでみたら、読み込む時は Moment.js を使って読み込んでいたようだ。

ということは、 hexo new post の時に ISO8601 の形式で出力しておけば万事解決。

…のはずなんですが、どこを修正すればよいのかわかりませんでした。

仕方なく、 Perl で書き直すことにしました。

PerlでYAMLも再構築

dateISO8601 の形式でなかった場合は、そのローカルタイムのタイムゾーンであるとみなして、 ISO8601 の形式で書き直す、というふうにしました。

また、そうした時に、どのタイムゾーンの日付をファイルの基準にするのか悩ましいのですが、 UTC の時間にすることにしました。

なので、これまで書いてきた記事のファイルのパスも変更になります。

tools/rename_posts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#!/usr/bin/env perl
use utf8;
use strict;
use warnings;
use Path::Tiny qw(path);
use YAML ();
use Time::Moment ();
my $root = path(__FILE__)->absolute->parent(2);
# 記事を取得
my $posts_dir = path($root, 'source', '_posts');
my $iterator = $posts_dir->iterator(+{recurse => 1});
# タイムゾーンを取得
my $tm = Time::Moment->now;
my $offset = $tm->offset;
# 記事から時間を取得して、名称変更
while (my $post = $iterator->()) {
next unless $post->is_file;
my ($yaml, $after) = split /\n---/, $post->slurp_utf8;
my $info = YAML::Load($yaml);
# 時間がISO8601でない場合は変換
if (-1 < index($info->{date}, ' ')) {
my $date = join('T', split(/\s/, $info->{date})) . 'Z';
my $tm = Time::Moment->from_string($date);
my $new_date = $tm->with_offset_same_local($offset);
$info->{date} = $new_date->to_string;
# 結合して出力
my $dump_yaml = YAML::Dump($info);
my $body = join qq{\n---}, $dump_yaml, $after;
$post->spew_utf8($body);
}
# 時間でファイル名を変更
my $tm = Time::Moment->from_string($info->{date})->at_utc;
my $path = $tm->strftime('%Y/%m/%d/%H%M%S');
my $new_post = path($posts_dir, qq{$path.md})->absolute;
$new_post->parent->mkpath;
$post->move($new_post->stringify);
}