【发布时间】:2011-10-01 03:46:20
【问题描述】:
在 Perl 中循环两个日期的最佳/最清晰的方法是什么? CPAN 上有很多模块可以处理此类问题,但是是否有任何经验法则可以在两个日期之间进行迭代?
【问题讨论】:
在 Perl 中循环两个日期的最佳/最清晰的方法是什么? CPAN 上有很多模块可以处理此类问题,但是是否有任何经验法则可以在两个日期之间进行迭代?
【问题讨论】:
对于所有使用日期操作的东西,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
【讨论】:
$start 之后的第二天开始的
如今,大多数人会推荐使用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);
}
【讨论】:
我提供了一个 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::Piece 和 Time::Seconds 都是 perl 5.9.5 的核心。后者仅对 ONE_DAY 需要 - 否则您可以添加 60 * 60 * 24 代替。
这具有能够解析相当任意的日期格式的优势。
【讨论】:
我认为做到这一点的“最佳”方式很大程度上取决于这两天你在做什么。
在许多情况下,一个简单的for (0..31) 循环就足够了。
在其他情况下,您可能希望使用 epoch 值,并在每次迭代时加/减 86400 秒。
在我编写的一个应用程序中,我正是这样做的,使用一个DateTime 对象,我为每次迭代添加一天。不过,这对于许多应用程序来说可能是多余的。
【讨论】:
从 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::Piece 和DateTime 相比,它会有所帮助。另外,界面非常易于阅读。日期解析功能可能限制较少。
【讨论】: