Time::Moment 可节省时间

很久以前,在一个遥远的星系中,叛军联盟遇到了一个小问题,因为载着公主的飞船因软件处于错误时区而晚出发了两小时,遇到了提前一小时巡逻的帝国巡洋舰。坏人们在移除那个特殊案例时无意中解决了叛军的问题,移除了错误的时区——这是一个程序员熟悉的解决方案。叛军在他们的防御留下一个实体的洞时,无意中利用了帝国的漏洞。

你可能认为我们现在正处于计算机革命之中(Alan Kay 说我们不是),但我们拥有所有这些华丽的硬件,廉价的或免费的平台和服务,以及我们拥有的惊人的编程工具,我们处理时间和日期的方式通常是一团糟。Y2K 远不及这个。

当 Dave Rolsky 推出 DateTime 时,每个人都欣喜若狂。这是一件杰作般的软件,力求在纳秒和闰秒上做到一丝不苟。在此之前,我使用了一堆模块来处理日期,并避免使用日期数学。

DateTime 可以表示日期,并告诉我关于它们的各种信息,例如季度中的某一天,提供特定地区的名称,以有趣的方式格式化,还可以告诉我日期之间的差异。

use Date::Time;

my $dt = DateTime->new(
    year       => 2014,
    month      => 12,
    day        => 18,
    hour       => 12,
    minute     => 37,
    second     => 57,
    nanosecond => 0,
    time_zone  => 'UTC',
);

my $quarter = $dt->quarter;
my $day_of_quarter = $dt->day_of_quarter;

my $month_name = $dt->month_name;  # can be locale specific

my $ymd = $dt->ymd('/'); # 2015/02/06

my $now = DateTime->now;

my $duration = $now - $dt;

DateTime 不解析日期。同一命名空间中的其他模块可以做到这一点,同时返回一个 DateTime 对象。例如,DateTime::Format::W3CDTF 模块解析日期并将它们转换为对象。

use DateTime::Format::W3CDTF;

my $w3c = DateTime::Format::W3CDTF->new;
my $dt = $w3c->parse_datetime( '2003-02-15T13:50:05-05:00' );

# 2003-02-15T13:50:05-05:00
$w3c->format_datetime($dt);

太棒了。 DateTime 是任何日期问题的标准答案。它几乎不需要我思考就能工作。

DateTime 有一个问题。它创建了大对象,在兴奋地使用一些可以工作的东西(慢而正确比快而错误要好)时,我可能会最终拥有数百个这样的对象,没有留下太多空间给其他东西。尝试将其中一个对象转储以查看其范围。我不会在这篇文章中浪费空间。

尽管 DateTime 非常精确,有时我希望能稍微不那么精确,并且要快得多。这就是 Christian Hansen 的 Time::Moment 的作用(参见他的 Time::Moment vs DateTime)。它使用 UTC,忽略闰秒,并将日期限制在公元1年至9999年之间。它的对象是不可变的,因此它可以稍微快一点。要获取新的日期时间,您会得到一个新的对象。它还具有许多常见功能和接近 DateTime 的接口。

Time::Moment 发行版附带一个程序 dev/bench.pl,它允许我比较性能。以下是一些输出结果

$ perl dev/bench.pl
Benchmarking constructor: ->new()
                  Rate     DateTime Time::Moment
DateTime       14436/s           --         -99%
Time::Moment 1064751/s        7276%           --

让我们做一个更有趣的基准,从一个字符串中构造一个对象,向它添加一天,并检查它是否在今天之前。像每个基准一样,您必须根据您的特定用途进行检查

use Benchmark;
use DateTime;
use Time::Moment;
use DateTime::Format::W3CDTF;

my $dtf_string ='2014-02-01T13:01:37-05:00';

my $time_moment = sub {
    my $tm = Time::Moment->from_string( $dtf_string );
    my $tm2 = $tm->plus_days( 1 );

    my $now = Time::Moment->now;

    my $comparison = $now > $tm2;
    };

my $datetime = sub {
    my $w3c = DateTime::Format::W3CDTF->new;
    my $dt = $w3c->parse_datetime( $dtf_string );
    $dt->add( days => 1 );

    my $now = DateTime->now;

    my $comparison = $now > $dt;
    };

Benchmark::cmpthese( -10, {
    'Time::Moment' => $time_moment,
    'DateTime'     => $datetime,
    });

Time::Moment 仍然非常快。令人惊讶地快

$ perl dtf_bench.pl
                 Rate     DateTime Time::Moment
DateTime       1889/s           --         -99%
Time::Moment 273557/s       14384%           --

如果我的问题在 Time::Moment 的限制内(谁会需要超过640k?),我可以获得巨大的收益。当这不再适用时,我可以通过一点工作切换到 DateTime。无论如何,你可能想要擦除你的机器人的记忆。

封面图片 © XKCD


本文最初发布在 PerlTricks.com

标签

布莱恩·D·福伊

布莱恩·D·福伊是一位Perl培训师和作家,同时也是Perl.com的高级编辑。他是《精通Perl》、《Mojolicious Web Clients》、《Learning Perl Exercises》等书的作者,以及《Programming Perl》、《Learning Perl》、《Intermediate Perl》和《Effective Perl Programming》等书的合著者。

浏览他们的文章

反馈

这篇文章有什么问题吗?请在GitHub上打开一个issue或pull request来帮助我们,链接为:GitHub