Date::Manip

日付処理は面倒です。いろいろな形式が混在します。ひとつくらいなら正規表現で済ませてしまえばいいんですが2つ3つとなると判定すら面倒くさくなってきます。

最初にこのモジュールですが、タイムゾーンが決まってないといけません。
ドキュメントを見ると

$Date::Manip::TZ (set with Date_Init or in Manip.pm)
$ENV{TZ}
the unix `date` command (if available)
$main::TZ
/etc/TIMEZONE
/etc/timezone

上から順に設定されているか見て、なかったら下へ行くようです。スクリプトの中で

$Date::Manip::TZ="JST" #or
Date_Init("TZ=JST")    #or
$main::TZ="JST"

と書くか、あるいはシェルかプロンプトで

set TZ="JST"    #at Win
export TZ="JST" #at Linux

としなければいけないようです。

やっと設定が終わって軽く使ってみると、なぜか今の時間が出てきません。そのあっていない時間をよく見てみると9時間前なわけです。なんでかなぁ?とおもいつつドキュメントを見てみるとTimeZoneの設定項目あたりにConvTZという項目を発見。もしやと思いTZのセットと同時に

Date_Init("TZ=JST","ConvTZ=JST");

と書いたところ正常な時間を返すようになりました。もうちょっとスマートな方法はないんでしょうか。

さて、前置きが長くなりましたけど使えるようになったのならばこっちのもんです。とりあえずひとつ、ParseDateという関数だけをとりあえず覚えればいいと思います。このモジュールといえばParseDate関数とも言わんばかりに便利で汎用的で、なおかつよく使います。ParseDate関数はYYYYMMDDHH:MM:SS形式で返されます。この返された形式を任意の形式に計算するためにもうひとつUnixDateという関数があります。これも覚えましょう。形式についてはドキュメントを見てください。

print UnixDate(ParseDate("Thu Feb 23 19:38:39 2006"),"%Y/%m/%d %H:%M:%S");  #2006/02/23 19:38:39
print UnixDate(ParseDate("2006/02/23 19:38:39"),"%Y/%m/%d %H:%M:%S");  #2006/02/23 19:38:39

もちろんこれでも十分使えるんですが

for ("now","+1 hour","tomorrow","next sunday","next month","+1 year")
{
  printf "%-12s : %s\n",$_,UnixDate(ParseDate($_),"%Y/%m/%d %H:%M:%S");
}

データが多いのでforで回します。出力。

now          : 2006/02/23 20:05:09
+1 hour      : 2006/02/23 21:05:09
tomorrow     : 2006/02/24 20:05:09
next sunday  : 2006/02/26 00:00:00
next month   : 2006/03/23 00:00:00
+1 year      : 2007/02/23 20:05:09

なんと口語表現まで解釈してくれちゃいます。初めて触ったときにはかなり感動しました。

なんかParseDate関数すげすげすげーな内容でしたがこのモジュールには他の関数もあります。しかしこの関数しか使ってません。それほど偉大な関数です。

TZの設定の詳細、タイムフォーマットの例、他の関数等はこちらのドキュメントからどうぞ。