phpのmktime
(;゚ Д゚)2秒…?
PHPで時刻の計算が異常に遅い例 - hnwの日記
僕のマシンがいくら遅いといってもこれは遅すぎなのでは…。ちなみにPHP5.0.5はライブラリコールを使っており、この環境では負のunix timeを正しく返しているわけですが、PHPの自前実装版に比べると100倍くらい早いみたいですね。
phpのmktimeがナイーブな独自実装しているため,正規ではない値を与えると遅くなるという話.
こんなことやっているのか.
static int do_range_limit(timelib_sll start, timelib_sll end, timelib_sll adj, timelib_sll *a, timelib_sll *b) { if (*a < start) { *a += adj; (*b)--; return 1; } if (*a >= end) { if (start == 0) { (*b) += (*a / end); (*a) -= (end * (*a / end)); return 0; } *a -= adj; (*b)++; return 1; } return 0; } ... static void do_normalize(timelib_time* time) { do {} while (do_range_limit(0, 60, 60, &time->s, &time->i)); do {} while (do_range_limit(0, 60, 60, &time->i, &time->h)); do {} while (do_range_limit(0, 24, 24, &time->h, &time->d)); do {} while (do_range_limit(1, 13, 12, &time->m, &time->y)); do {} while (do_range_limit_days(&time->y, &time->m, &time->d)); do {} while (do_range_limit(1, 13, 12, &time->m, &time->y)); }
上記はphp-5.2.4のext/date/tm2unixtime.c.do_normalizeは300秒→5分のように正規ではない値を正規化する関数.で,do_range_limitは何をしているかというと,0〜60秒の範囲に無いと,±60秒→±1分という操作を行っているので,秒がはみ出しているサイズに比例して時間がかかってる
正規化の機能はoptionalだと思うのでまあいいのかな.
perl場合もちょっと調べてみる.ビルトイン関数にmktimeはないのだが,標準モジュールのTime::Local::timelocalなどがある.
pirl @> use Time::Local; () pirl @> timelocal(-2147483647,0,9,1,0,1970) ERROR: Second '-2147483647' out of range 0..59 at (eval 14) line 1
と,通常の場合は範囲チェックがされてエラーになるので,timelocal_nocheckを用いる.
pirl @> Time::Local::timelocal_nocheck(-2147483647,0,9,1,0,1970) -2147483647
と範囲外のものも計算してくれる.
コードはどうかというとtimelocalは内部で_timegmを呼んでいるのだが,
sub _daygm { $_[3] + ($Cheat{pack("ss",@_[4,5])} ||= do { my $month = ($_[4] + 10) % 12; my $year = $_[5] + 1900 - $month/10; 365*$year + $year/4 - $year/100 + $year/400 + ($month*306 + 5)/10 - $Epoc }); } sub _timegm { my $sec = $SecOff + $_[0] + 60 * $_[1] + 3600 * $_[2]; no integer; $sec + 86400 * &_daygm; }
_daygmの細かい計算がどうなっているのかよくわからないけど,大まかな流れはそのまま掛けて足している.繰り返しをしているわけではないので,PHPのように時間がかかったりはしない.