はちゅにっき

こっちのブログはまったり更新

DateTime の strftime('%z') がうれしくない

最近は AtomPub で遊んでます。
AtomPub というか、どちらかといえば Catalyst で AtomPubServer を作って遊んでいます。

特集:PerlでAtomPubサーバを作ろう!
http://gihyo.jp/admin/feature/01/atompub-server

すばらしい内容ですね!

で、そんな中こまったこと。
前の日記の続きと言えば続き。
Postgres の時間を DateTime::Fromat::Pg を使うことで DateTime 型に変換できるのはすごく嬉しかったんだけど、これを AtomFeed として利用しようとしたとき、strftime->('%z') で出力するタイムゾーン

$date->strftime('%z'); # => '+0900'

と "±HHMM" のフォーマットで出力されてしまうため、一部の "±HH:MM" 形式しか読み込めない RSS リーダで表示すると、時刻がタイムゾーン分狂ってしまうことに。。。*1
この表示ルールを定めている ISO 8601 的には ":" があってもなくてもいいような感じなんだけれども、他のサイトの RSS とかをのぞいてみると、圧倒的に "±HH:MM" 形式が多数でした。
って、みんなどうやって表示しているんだろう?
どちらにせよ、時間が狂っているのは嬉しくないので手を加えることに。

どこをなおす?

strftime が定義されているのは、DateTime.pm の900行目付近から。
そして、問題の '%z' が定義されているのは、956行目あたり

    'z' => sub { DateTime::TimeZone->offset_as_string( $_[0]->offset ) },

ということが分かりました。

どうじっそうする?

DateTime::TimeZone#offset_as_string を直接修正してもいいし '%z' の挙動を変更してもいいんだけれど、どこか他の場所で利用されていると困るので直接書き込むのはやめといて、DateTime を継承したモジュールを作って、strftime をオーバーライドすること。。。にしようと思ったんだけれど、いろいろとワケあって、直接書き込むことにしました。

てきとうにかいた

'%z' の挙動を変えてしまうのには抵抗があったので、利用されていない文字で、新たなパターンを生成してしまうことに。
今回は '%Q' って書くと 'HH:MM' で表示するようにしました。
そんなわけで、以下↓を加筆しました。

    'Q' => sub {
        my $str = DateTime::TimeZone->offset_as_string( $_[0]->offset );
        $str =~ /^([-\+]\d{2})(\d{2})$/;
        $1.':'.$2;
    },

これで

$date->strftime('%z | %Q'); # => '+9000 | +09:00'

と、'%Q' を使うことで期待するタイムゾーンの書式を得ることができました。
わーい。

*1:Firefox 内臓の RSS リーダとか!