Time::Piece(Time::Seconds)のONE_MONTHでうっかりやってしまった

「2011-10-01 00:00:00」の一ヶ月前のTime::Pieceオブジェクトを取得したいというような場合に「$t -= ONE_MONTH」みたいなコードを書いたら意図しない結果になってしまった。詳しくはhttp://blog.clouder.jp/archives/000409.htmlに書いてある通り。以下はよろしくないサンプルとそれの代替となるコード。

use strict;
use warnings;
use Time::Piece;
use Time::Seconds;
use Perl6::Say;

for my $month ( 1 .. 12 ) {
    my $date = sprintf "2011-%02d-01 00:00:00", $month;
    my $t = Time::Piece->strptime( $date, '%Y-%m-%d %H:%M:%S' );
    my $t2 = $t - ONE_MONTH;

    my $format = '%Y-%m-%d %H:%M:%S';
    printf "%s\t%s\n", $t->strftime($format), $t2->strftime($format);
}
## 2011-01-01 00:00:00     2010-12-01 13:30:56
## 2011-02-01 00:00:00     2011-01-01 13:30:56
## 2011-03-01 00:00:00     2011-01-29 13:30:56
## 2011-04-01 00:00:00     2011-03-01 13:30:56
## 2011-05-01 00:00:00     2011-03-31 13:30:56
## 2011-06-01 00:00:00     2011-05-01 13:30:56
## 2011-07-01 00:00:00     2011-05-31 13:30:56
## 2011-08-01 00:00:00     2011-07-01 13:30:56
## 2011-09-01 00:00:00     2011-08-01 13:30:56
## 2011-10-01 00:00:00     2011-08-31 13:30:56
## 2011-11-01 00:00:00     2011-10-01 13:30:56
## 2011-12-01 00:00:00     2011-10-31 13:30:56

これをTime::Piece::Monthを使って正しくすっきりと書く。

use strict;
use warnings;
use Time::Piece::Month;
use Perl6::Say;

for my $month ( 1 .. 12 ) {
    my $date = sprintf "2011-%02d-01 00:00:00", $month;
    my $t = Time::Piece->strptime( $date, '%Y-%m-%d %H:%M:%S' );
    my $month = Time::Piece::Month->new($t);

    my $format = '%Y-%m-%d %H:%M:%S';
    printf "%s\t%s\t%s\n", $t->strftime($format),
      $month->next_month->end->strftime($format),
      $month->prev_month->start->strftime($format);
}
## 2011-01-01 00:00:00     2011-02-28 00:00:00     2010-12-01 00:00:00
## 2011-02-01 00:00:00     2011-03-31 00:00:00     2011-01-01 00:00:00
## 2011-03-01 00:00:00     2011-04-30 00:00:00     2011-02-01 00:00:00
## 2011-04-01 00:00:00     2011-05-31 00:00:00     2011-03-01 00:00:00
## 2011-05-01 00:00:00     2011-06-30 00:00:00     2011-04-01 00:00:00
## 2011-06-01 00:00:00     2011-07-31 00:00:00     2011-05-01 00:00:00
## 2011-07-01 00:00:00     2011-08-31 00:00:00     2011-06-01 00:00:00
## 2011-08-01 00:00:00     2011-09-30 00:00:00     2011-07-01 00:00:00
## 2011-09-01 00:00:00     2011-10-31 00:00:00     2011-08-01 00:00:00
## 2011-10-01 00:00:00     2011-11-30 00:00:00     2011-09-01 00:00:00
## 2011-11-01 00:00:00     2011-12-31 00:00:00     2011-10-01 00:00:00
## 2011-12-01 00:00:00     2012-01-31 00:00:00     2011-11-01 00:00:00

ほんのちょっとテストする時間をけちった結果は高くつきました。。コードを書けば書くほど自分の粗がぼろぼろと出てきてちょっと鬱。