てきとうなメモ

本の感想とか技術メモとか

phpのmktime

(;゚ Д゚)2秒…?
僕のマシンがいくら遅いといってもこれは遅すぎなのでは…。ちなみにPHP5.0.5はライブラリコールを使っており、この環境では負のunix timeを正しく返しているわけですが、PHPの自前実装版に比べると100倍くらい早いみたいですね。

PHPで時刻の計算が異常に遅い例 - hnwの日記

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のように時間がかかったりはしない.