その月の最後の日を返すサブルーチンをちょっと加工すれば、日付が有効なものかどうかをチェックするサブルーチンを作ることができます。
# 年と月と日から有効な日付かどうかをチェック
sub day_check {
my($year, $month, $day) = @_;
# うるう年を考えない場合の、月の最終日のリスト
my(@lastday) = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
# 月が1から12でないならこの時点でゼロを返す
if ($month < 1 || 12 < $month) {
return 0;
}
# 2月の場合、閏年であれば日数を増やす
if ($month == 2) {
if ( (($year % 4 == 0) && ($year % 100 != 0)) || ($year % 400 == 0) ) {
$lastday[1]++;
}
}
# 有効な日付かどうかをチェック
if ($day < 1 || $lastday[$month - 1] < $day) {
return 0;
}
return 1;
}
※閏年の算定についてはその月の最後の日を返すサブルーチンをご覧ください。
このサブルーチンは、たとえば日付のタイムスタンプを1ずつ増やしながらループさせるとき等に役立ちます(「26日」から「5日分」とかね)。そのループで使用するタイムスタンプが7月のものであることがわかっていれば、単純に「26日」から「31日」までのループでOKですが、7月のものであると確定できない場合は、ループ内で日付が有効かどうかチェックする必要があるでしょう。
たとえば以下のように、クエリから年月日のみ(8桁)のタイムスタンプを受け取って、それから5日後までの有効な日付を順に出力し、日付が有効でなければ処理を終了する必要がある場合などが考えられます。
use CGI;
my $query = new CGI;
my $timestamp = $query->param('timestamp');
for (my $i = 0; $i < 5; $i++){
my $target = $timestamp + $i;
# 有効な日付かどうかをチェック
my $year = substr($target, 0, 4);
my $month = substr($target, 4, 2);
my $day = substr($target, 6, 2);
my $result = &day_check($year, $month, $day);
# チェック結果により分岐処理、日付が有効でないなら処理終了
if ($result == 1) {
print "$timestamp\n";
} else {
last;
}
}
5日分に限らず、渡された日から月末までを処理すればよいのであれば、その月の最後の日を返すサブルーチンを使って、ループ処理の終了条件を指定してもよいと思います。
use CGI;
my $query = new CGI;
my $timestamp = $query->param('timestamp');
# 月の最後の日付を受け取る
my $year = substr($timestamp, 0, 4);
my $month = substr($timestamp, 4, 2);
my $day = substr($timestamp, 6, 2);
my $end_day = &last_day_of_month($year, $month);
my $loop_num = $end_day - $day;
for (my $i = 0; $i < $loop_num; $i++){
my $datetime = $timestamp + $i;
print "$datetime\n";
}
※サブルーチンlast_day_of_monthについてはその月の最後の日を返すサブルーチンをご覧ください。
Comments