Hachioji.pm 日めくりテックトーク

Time::PieceのParseで%zを使うのは無理ゲー

「タイムゾーンマタギはおいておいて、そうでないケースにおいて、Date::Timeはオワコンで、Time::Pieceが主流」的なノリになってからだいぶ長いですが、最近やっとTime::Pieceを使い始めたのですが、メールのヘッダーのDateのところをぴっぱろうとしたらはまったんで、そのあたりをまとめておきます。あまり、直接的なタイトルの日本語記事がなかったので。

ダメのコード

さて、問題となる具体的なコードは以下です。

#!/usr/bin/env perl
use strict;
use warnings;
use utf8;
use Time::Piece;

{
    my $datetime = "Thu, 28 Nov 2013 18:32:29 +0900 (JST)";
    my $t = localtime(Time::Piece->strptime($datetime,'%a, %d %h %Y %H:%M:%S %z (%Z)'));
    warn $t->datetime; # 2013-11-28T09:32:29
}

{
    my $datetime = "Thu, 28 Nov 2013 18:32:29";
    my $t = localtime(Time::Piece->strptime($datetime,'%a, %d %h %Y %H:%M:%S'));
    warn $t->datetime; # 2013-11-28T18:32:29
}

日付の書式指定にあるように、日付をいろいろパースするときの記号はいろいろあるわけですが、「%z」という「+0900」という「タイムゾーンのGMTへのオフセット時間」ってやつが、Time::Pieceでうまくいかないのはご存知でしょうか。

下の方ではしっかりパースできるのに、上の「+0900 (JST)」のコードのほうが、見事に9時間ズレてしまっています。

既存文献と対応方法

重要な問題だからこそでしょうがTime::Piece::strftime and time zone issueという英語の記事でtokuhiromさんが、問題と対応方法を書いているんですが、なんかややっこしいので、どうしたものかと思ったら、sonmguさんが、HTTP::Dateを使うのがいいかもねって教えてもらったので、ぼくはそうしました。

use HTTP::Date;

my $datetime = "Thu, 28 Nov 2013 18:32:29 +0900 (JST)";
my $t = localtime(HTTP::Date::str2time(HTTP::Date::parse_date($datetime)));
warn $t->datetime; # 2013-11-28T18:32:29 

まぁ便利でわかりやすい。Date::Time使うのとCPUとかメモリのコストがどれほど違うのかよくわかりませんが、わかりやすさ間違いないでしょう。毎度、sonmgu++という感じでいつか恩返ししなきゃいけないところです。

終わりに

日付周りのモジュールは何が何だったかすっかり忘れてことが多いので、しっかりメモっておきたい今日この頃です。

こういう軽いTipsをこちこちやっていきたいところです。年末はたくさんアドベントカレンダーあるんで、ちょっと胃もたれがちですからねー。

created by
Hiroyuki Akabane
created at
last modified at
2013-12-07 19:27
comments powered by Disqus