なんか周りの人に聞くと常識だったようですが、PerlのTime::Pieceモジュールと共に使用して時間の増減等の計算をする際に使用するTime::Secondsモジュールにヤラれました。 毎月1回実行するプログラムがあり、その実行日の「一月前」を取得したかったのですが(つまり、「2005-05-01」だったら「2005-04-01」を取得、「2005-03-01」だったら「2005-02-01」を取得)、下記のように書いてしまいました。
use Time::Piece;
use Time::Seconds;

my $t = localtime;
my $before_one_month = $t - ONE_MONTH;
わかる人にはわかると思いますが、これではぜんぜんやりたいことをやれていません…。結論から言うと、上記で使用している、ONE_MONTH(Time::Seconds::ONE_MONTH)が希望したものではなかったからです。 Time::Secondsのモジュールの中では下記のような定義がなされています。
use constant ONE_MONTH => 2_629_744; # ONE_YEAR / 12
これは、1年を365.24225日として、それを秒数に直すと31556930.4秒なので、これを12で割った値2629744.2秒(モジュール内では、0.2を省いて2629744秒)を1ヶ月としているという意味になるので、イコールONE_MONTHは30.436851851851851851851851851852日ということになります。てかそもそも定数な時点でこの計算が希望するものになっていないことはわかるんですけどね。それだったらONE_MONTHって名前じゃなくてTHIRTY_DAYSとかにしろー。とここでぼやいても始まりませんが…。 ということで、1ヶ月の日数が31日未満の月の次の月に $t - ONE_MONTH を処理すると一つ月を飛び越えてしまいます。(3月だったら1月に、5月だったら3月になる。) でも、1月と2月にこの処理をすると問題なく動くので、その結果をみて「動いてる動いてる」と安心してしまった自分が馬鹿でした。 もっと検証には慎重にならなければと思った出来事でした。