time() は、グリニッジ標準時 1970年1月1日0時0分0秒を 0 とした現時刻の秒数を返します。gmtime() や localtime() はこの時刻を年、月、日、時、分、秒に分解します。gmtime() はグリニッジ標準時における値を、localtime() は現地時刻の値を返します。
$ENV{'TZ'} = "JST-9"; @wdays = ( "日", "月", "火", "水", "木", "金", "土"); $time = time(); ($sec, $min, $hour, $mday, $mon, $year, $wday) = localtime($time); printf("%04d/%02d/%02d %02d:%02d:%02d(%s)\n", $year + 1900, $mon + 1, $mday, $hour, $min, $sec, $wdays[$wday]);
実行結果は次のようになります。
2002/02/11 01:13:59(月)
$year には 1900 年からの差分が返されます。また、$mon には月から 1 を引いた値(0~11)が返されますので注意してください。
プログラムの最初の方で $ENV{'TZ'} を設定しておかないと、時間帯が狂うことがあります。"JST-9" は「日本時間、標準時から -9 時間のずれ」を意味しています。例えば、アメリカ東部標準時間(EST)での時刻を求めるには次のようにします。
$ENV{'TZ'} = "EST+5"; @wdays = ( "日", "月", "火", "水", "木", "金", "土"); $time = time(); ($sec, $min, $hour, $mday, $mon, $year, $wday) = localtime($time); printf("%04d/%02d/%02d %02d:%02d:%02d(%s)\n", $year + 1900, $mon + 1, $mday, $hour, $min, $sec, $wdays[$wday]);
ただし、システムによっては、環境変数 TZ の値を参照しないものもあるようです。
stat() や lstat() を用いて、ファイルの最終更新時刻を得ることができます。返される時間は 1970年1月1日からの秒数なので、localtime() を用いて年月日時分秒に分解します。
$ENV{'TZ'} = "JST-9"; @wdays = ( "日", "月", "火", "水", "木", "金", "土"); $mtime = (stat("file.txt"))[9]; ($sec, $min, $hour, $mday, $mon, $year, $wday) = localtime($mtime); printf("%04d/%02d/%02d %02d:%02d:%02d(%s)\n", $year + 1900, $mon + 1, $mday, $hour, $min, $sec, $wdays[$wday]);
実行結果は次のようになります。
2002/02/11 01:16:50(月)
閏年(うるうどし)は西暦が4で割りきれる年です。ただし、100で割りきれる年は閏年ではありません。ただし、400で割りきれるときは閏年となります。
sub IsLeapYear { local($year) = @_; if (($year % 400) == 0) { return 1; } if (($year % 100) == 0) { return 0; } if (($year % 4) == 0) { return 1; } return 0; } for ($year = 1998; $year < 2002; $year++) { if (IsLeapYear($year)) { print "$year年は閏年です。\n"; } else { print "$year年は閏年ではありません。\n"; } }
実行結果は次のようになります。2000年は 100でも割り切れますが、400でも割り切れるので閏年となります。
1998年は閏年ではありません。 1999年は閏年ではありません。 2000年は閏年です。 2001年は閏年ではありません。
localtime() とは逆に、現地時刻の年、月、日、時、分、秒から、グリニッジ標準時 1970年1月1日0時0分0秒からの秒数を求めるには、Time::Local モジュールの timelocal() を用います。
use Time::Local; $year = 1999; $mon = 12; $mday = 31; # 1999年12月31日 $hour = 23; $min = 59; $sec = 59; # 23時59分59秒 $time = timelocal($sec, $min, $hour, $mday, $mon - 1, $year - 1900); print "$time\n";
結果は次のようになります。
946652399
$year は 1900年からの差分、$mon は 0~11 の値で指定するので注意してください。
POSIX モジュールの mktime() を用いても同じことができます。
use POSIX; $year = 1999; $mon = 12; $mday = 31; # 1999年12月31日 $hour = 23; $min = 59; $sec = 59; # 23時59分59秒 $time = mktime($sec, $min, $hour, $mday, $mon - 1, $year - 1900); print "$time\n";
結果は次のようになります。
946652399
1992年4月11日12時34分56秒は、2002年12月31日19時45分12秒の何日と何時間前でしょうか。このような時刻の差分を計算する場合、両者を一度1970年1月1日からの秒数に変換し、この差分を求めることで計算できます。
use Time::Local; # 両者を一度 1970/01/01 00:00:00 からの秒数に変換する $t1 = timelocal(56, 34, 12, 11, 4 - 1, 1992 - 1900); $t2 = timelocal(12, 45, 19, 31, 12 - 1, 2002 - 1900); $diff = $t2 - $t1; # 秒数の差分を求める $days = int($diff / (3600 * 24)); # 日数を求める $diff %= (3600 * 24); $hours = int($diff / 3600); # 時間を求める $diff %= 3600; $minutes = int($diff / 60); # 分を求める $diff %= 60; $secs = $diff; # 秒数を求める print "$days日$hours時間$minutes分$secs秒前です。\n";
結果は次のようになります。
3916日7時間10分16秒前です。
Zellerの公式 を用いて、指定した日付の曜日を求めます。0 が日曜日、6 が土曜日になります。これは、1583年~3999年までの間で有効な公式だそうです。前出の mktime() や timelocal() を用いて1970年からの秒数を求め、これを localtime() にかけても算出できます。
@wdays = ( "日", "月", "火", "水", "木", "金", "土"); sub GetDate { local($yy, $mm, $dd) = @_; if (($mm == 1) || ($mm == 2)) { $yy--; $mm += 12; } return ($yy + int($yy / 4) - int($yy / 100) + int($yy / 400) + int(2.6 * $mm + 1.6) + $dd) % 7; } print "2001/12/31 は" . $wdays[GetDate(2001, 12, 31)] . "曜日です\n";
sleep() は指定した秒数だけ処理をスリープ(中断)して待ちます。例では、"A" を 1秒毎に10個書き出します。
for ($i = 0; $i < 10; $i++) { print "A\n"; sleep(1); }
select() を用いることにより、待ち時間をミリ秒の単位で指定することができます。例では、"B" を 0.5秒毎に 10個書き出します。
for ($i = 0; $i < 10; $i++) { print "B\n"; select(undef, undef, undef, 0.5); }
times() は、プロセスや子プロセスが消費したユーザCPU時間とシステムCPU時間を秒単位で返します。
($user1, $system1, $c_user1, $c_system1) = times(); for ($i = 0; $i < 10; $i++) { system("netstat -a"); } ($user2, $system2, $c_user2, $c_system2) = times(); printf("ユーザ時間:%5.3f秒\n", $user2 - $user1); printf("システム時間:%5.3f秒\n", $system2 - $system1); printf("子プロセスユーザ時間:%5.3f秒\n", $c_user2 - $c_user1); printf("子プロセスシステム時間:%5.3f秒\n", $c_system2 - $c_system1);
実行結果は次のようになります。(結果表示部分のみ)
ユーザ時間:0.016秒 システム時間:0.016秒 子プロセスユーザ時間:0.000秒 子プロセスシステム時間:0.000秒
この値を測定することにより、プロセスがどのくらい、CPU に負荷をかけているかを計測することが可能になり、システム高速化検討の目安となります。
stat() と lstat() はどちらの方がどのくらいパフォーマンスがよいでしょうか。stat() や lstat() の処理時間を測定できればよいのですが、処理の前後で time() を取得して差分をとっても、大抵が 0 秒となってうまく計測できません。この場合、処理を繰り返して差分が発生する確率を求めることにより、パフォーマンスの推定を可能にする方法が考えられます。
open(IN, "data.txt"); for ($i = 0; $i < 10000; $i++) { $t1 = time(); lstat(IN); # 処理1 $t2 = time(); stat("stat.txt"); # 処理2 $t3 = time(); $tt1 += ($t2 - $t1); # 処理1に要した時間の合計 $tt2 += ($t3 - $t2); # 処理2に要した時間の合計 } close(IN); print "処理1 = $tt1\n"; print "処理2 = $tt2\n";
実行結果の例は例えば次のようになります。
処理1 = 2 処理2 = 16
結果からは、処理1(lstat)よりも処理2(stat)の方が、8倍も遅いことが分ります。結果に差異が現れない場合は、ループの回数(例では 10000)を増やしてみてください。