試しにISO8601で書いてみたら動いた
アメリカに来て、 hexo new post
としてみたところ、やはり date
はローカルタイムで作成されていた。
ふと思いついて、 date
の部分を ISO8601
の形式で書いてみたところ、正常に読み込めた。
Hexoのソースコードを読んでみた
どういうことかと思ってソースコードを読んでみたら、読み込む時は Moment.js
を使って読み込んでいたようだ。
ということは、 hexo new post
の時に ISO8601
の形式で出力しておけば万事解決。
…のはずなんですが、どこを修正すればよいのかわかりませんでした。
仕方なく、 Perl で書き直すことにしました。
PerlでYAMLも再構築
date
が ISO8601
の形式でなかった場合は、そのローカルタイムのタイムゾーンであるとみなして、 ISO8601
の形式で書き直す、というふうにしました。
また、そうした時に、どのタイムゾーンの日付をファイルの基準にするのか悩ましいのですが、 UTC
の時間にすることにしました。
なので、これまで書いてきた記事のファイルのパスも変更になります。
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);
}
|