在Perl中两个日期之间循环的最佳方法是什么?

时间:2011-07-08 09:57:17

标签: perl date loops iteration

在Perl中两个日期之间循环的最佳/最清晰的方法是什么? CPAN上有很多模块可以解决这个问题,但是在两个日期之间迭代是否有任何经验法则?

5 个答案:

答案 0 :(得分:29)

对于使用日期操作的所有内容DateTime可能是最好的模块。要使用您自己的增量获取两个日期之间的所有日期,请使用以下内容:

#!/usr/bin/env perl
use strict;
use warnings;
use DateTime;

my $start = DateTime->new(
    day   => 1,
    month => 1,
    year  => 2000,
);

my $stop = DateTime->new(
    day   => 10,
    month => 1,
    year  => 2000,
);


while ( $start->add(days => 1) < $stop ) {
    printf "Date: %s\n", $start->ymd('-');
}

这将输出:

Date: 2000-01-02
Date: 2000-01-03
Date: 2000-01-04
Date: 2000-01-05
Date: 2000-01-06
Date: 2000-01-07
Date: 2000-01-08
Date: 2000-01-09

答案 1 :(得分:6)

现在,大多数人会建议使用DateTime

use DateTime;   

my $start = DateTime->new(...); # create two DateTime objects
my $end   = DateTime->new(...);

while ($start <= $end) {
    print $start->ymd, "\n";
    $start->add(days => 1);
}

答案 2 :(得分:3)

我正在提供一个Time::Piece解决方案,因为 - 与DateTime不同,它是一个核心模块(截至perl 5.9.5):

#!/usr/bin/env perl

use strict;
use warnings;
use Time::Piece;
use Time::Seconds;

my $FORMAT = '%Y-%m-%d';

my $start = '2016-01-22';
my $end   = '2016-03-11';


my $start_t = Time::Piece->strptime( $start, $FORMAT );
my $end_t   = Time::Piece->strptime( $end,   $FORMAT );

while ( $start_t <= $end_t ) {
   print $start_t ->strftime($FORMAT), "\n";
   $start_t += ONE_DAY;
}

Time::PieceTime::Seconds都是perl 5.9.5的核心。后者仅在ONE_DAY时需要 - 否则您只需添加60 * 60 * 24即可。

这样做的好处是能够解析相当任意的日期格式。

答案 3 :(得分:1)

我认为做到这一点的“最佳”方式很大程度上取决于这两天之间你正在做什么

在许多情况下,简单的for (0..31)循环就足够了。

在其他情况下,您可能希望使用纪元值,并在每次迭代时加/减86400秒。

在我编写的一个应用程序中,我正是这样做的,使用我为每次迭代添加一天的DateTime对象。但是,对于许多应用程序而言,这可能有点过头了。

答案 4 :(得分:0)

从2020年开始,另一种选择是使用Time::Moment,它们通过清晰的界面具有非常好的性能(请参阅the benchmarks)。

重新实现Sobrique的答案是:

#!/usr/bin/env perl

use strict;
use warnings;
use Time::Moment;

# Same than 'Y-%m-%d'
my $FORMAT = '%F';

my $start = '2020-01-22';
my $end   = '2020-03-11';

my $start_t = Time::Moment->from_string( $start . 'T00Z' );
my $end_t   = Time::Moment->from_string( $end . 'T00Z' );

while ( $start_t <= $end_t ) {
   print $start_t ->strftime( $FORMAT ), "\n";
   $start_t->plus_days( 1 );
}

Time::Moment不是核心模块,但是如果需要额外的速度,与Time::PieceDateTime相比,它可以有所帮助。另外,该界面非常易于阅读。日期解析功能的限制可能会少一些。