2ヶ月前の末日を取り出す

例えば今日(10/11)なら、8/31を取り出したい。これが思ったより厄介な問題だ。原因は1ヶ月の日数が一定ではないという点。例え10/11から8月という月を取り出すだけであっても、単純に60日分の秒数を引けばよいということにはならない。

1ヶ月で考えればよく分かる。例えば10/31の30日前は10/01だし、9/30の30日前なら8/31、3/1の30日前は1月だ。面倒。

その辺をクリアすべく作ったのが下。

use strict;
use Time::Piece;
my $t = localtime;

my $y = $t->year;
my $m = $t->mon - 2; # 2ヶ月前は何月?
if( $m <= 0 ){
    $y -= 1;
    $m += 12;
}
printf "%04d-%02d-%02d",
    $y, $m, Time::Piece
        ->strptime("$y-$m-01","%Y-%m-%d")
            ->month_last_day;
exit;

まず起点の月の『数』を取り出し、単純に引き算する。引き算の結果が0や負なら、それは前年ということなので年から1引き、月に12加える。そうして年と月が分かったら、適当に整形してTime::Piece::strptimeでパースしてmonth_last_dayで末日を取り出し、最後に整形。

たかが2ヶ月前の末日を取り出すだけなのに、大げさなロジックだなぁとか思ったり。