特定の日付の曜日を計算する
結構これでハマる人は多いみたいです。
以下のようにtimelocal.plや、Time::Localを使う方法も
あります(以下参照)が、
use Time::Local;
$time = timelocal(0, 0, 0, 1, $mon, $year);
($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
localtime($time);
print ('日', '月', '火', '水', '木曜', '金', '土')[$wday];
○実行効率が悪い(遅い)
○計算できる範囲がOSやTime::Localの制限を受ける
○(FreeBSD/perl5.004_04では1970年〜2037年頃まで)
*余談だけど昔のperl4のtimelocalのyearのところ
*に大きすぎる値(1999とか)を渡すと、core dumpし
*たり帰ってこなかったりするバグがあった。
などの点で汎用性は低いです。60年代生まれの人の誕生日の
曜日なんかはうまく計算できない場合が多いでしょう。
こういう場合はツェラー(Zellar)の公式が便利です。
sub getweek{
local($day, $year, $month) = @_;
# $year = 年; # もちろん4桁で。
# $month = 月; # 1-12で。1月は1。
if ($month == 1 || $month == 2) {
$year--;
$month += 12;
}
int(
$year
+ int($year/4)
- int($year/100)
+ int($year/400)
+ int((13*$month+8)/5)
+ $day
) % 7;
}
こんな感じで。
この&getweekは引数に西暦(4桁)と月(1から12)、日にちを取り、0〜6
の数字を返します。0が日曜で6が土曜になっています。
というわけで今年の1月初日の曜日を表示するなら、
print ('Sun', 'Mon', ..略.., 'Sat')[&getweek(1999, 1, 1)];
の様に使えばうまく行きます。
カレンダーも作れます。
1752年10月 〜 9999年12月までの間ならcalコマン
ドと同じ結果を出すと思います。
#!/usr/local/bin/perl
# コマンドライン引数をもらう
die "usage: cal month year\n" unless @ARGV == 2;
($mon, $year) = @ARGV;
# その月の末日を計算(2行目は閏年の計算)
$lastday = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)[$mon - 1]
+ ($mon == 2 && ($year % 4 == 0 && $year % 100 != 0 || $year % 400 == 0));
print " $year/$mon\n S M Tu W Th F S\n";
foreach((" ") x &getweek($year, $mon), 1 .. $lastday){
printf ('%2.2s ' , $_);
print "\n" unless ++$days % 7;
}
print "\n"; exit;
# 曜日を得る関数
sub getweek{
local($year, $month) = @_;
if($month == 1 || $month == 2) {$year--;$month += 12;}
int($year + int($year/4) - int($year/100) + int($year/400) + int((13*$month+8)/5) + 1) % 7;
}