camel

私はあまりDateTimeは使ってないのだけど、better practiceを見つけたと思うので。

[perl] DateTime->now(time_zone => 'local')って激遅 - おいぬま日報(不定期) (2006-12-06)
Perl界隈の日付操作モジュールのデファクトスタンダードであるDateTimeですが、今まで「タイムゾーンなんてシステムで定義されているものから勝手に取ってきてほしい」という理由で

DateTime->now(time_zone => 'local');

なんてことをしてたのですが、これが激遅なことが発覚しました。

二行で書くと、以下のとおり。

my $tzhere = DateTime::TimeZone->new( name => 'local' );
my $dt = DateTime->now(time_zone => $tzhere);

要は、あらかじめDateTime::TimeZoneオブジェクトをこさえといて、それを使い回せということ。これだと明示指定以上に高速になるし、ポータビリティを損なうこともありません。

dtbench.pl
#!/usr/bin/perl
use strict;
use DateTime;
use DateTime::TimeZone;
use Benchmark qw/cmpthese timethese/;

sub gentest {
    my $tz = shift;
    sub { DateTime->now( time_zone => $tz ) }
}
my $tzhere = DateTime::TimeZone->new( name => 'local' );
my %these;
for my $tz ( 'local', 'Asia/Tokyo', $tzhere ) {
    my $name = ref($tz) ? q($tz) : qq('$tz');
    $these{ "now($name)" } = gentest($tz);
}
cmpthese( timethese( 0, \%these ) );
FreeBSD 6-STABLE
  now($tz):  3 wallclock secs ( 3.16 usr +  0.02 sys =  3.18 CPU) @ 2279.15/s (n=7247)
now('Asia/Tokyo'):  4 wallclock secs ( 3.19 usr +  0.02 sys =  3.20 CPU) @ 2029.58/s (n=6501)
now('local'):  4 wallclock secs ( 0.87 usr +  2.36 sys =  3.23 CPU) @ 67.25/s (n=217)
                    Rate      now('local') now('Asia/Tokyo')          now($tz)
now('local')      67.3/s                --              -97%              -97%
now('Asia/Tokyo') 2030/s             2918%                --              -11%
now($tz)          2279/s             3289%               12%                --
Mac OS X v10.4.8
 now($tz):  4 wallclock secs ( 3.23 usr +  0.02 sys =  3.25 CPU) @ 2871.08/s (n=9331)
now('Asia/Tokyo'):  3 wallclock secs ( 3.18 usr +  0.01 sys =  3.19 CPU) @ 2616.61/s (n=8347)
now('local'):  3 wallclock secs ( 3.09 usr +  0.16 sys =  3.25 CPU) @ 1767.38/s (n=5744)
                    Rate      now('local') now('Asia/Tokyo')          now($tz)
now('local')      1767/s                --              -32%              -38%
now('Asia/Tokyo') 2617/s               48%                --               -9%
now($tz)          2871/s               62%               10%                --

ちなみに、OS Xの方が差が少ないのは、/etc/localtimeがsymlinkだから。DateTime::TimeZoneはこの場合はSymlinkを読んでタイムゾーン名をすぐに割り出すのだけど、実ファイルの場合は、/usr/share/zoneinfo以下のファイルを全部File::Compareで比較するという涙ぐましい方法で調べます。

こんなところかな。

Dan the Man with Too Many Timezones to Cover