我正在从日志文件中读取,并希望将搜索限制到特定日期范围的选项。日志文件中的行格式为:May 27 09:33:33
。我已经在日志文件的每一行中将日期从其余文本中分离出来。我只想写这样的语句
if(the date falls between June 10th and June 20th)
作为一个例子,我想获取当前时间
use DateTime;
my $dt = DateTime->now;
my $date = $dt->md;
my $time = $dt->hms;
,但这不会是mm-dd的格式吗?
您应该使用时间戳/epoch进行比较。下面是一个例子:
#!/usr/bin/env perl
use DateTime::Format::Strptime;
use DateTime;
my $year = DateTime->now->year;
my $date_parser = DateTime::Format::Strptime->new(
pattern => '%Y %B %d', # YYYY Month DD
);
my $start_date = 'June 10';
my $end_date = 'June 20';
my $start_epoch = $date_parser->parse_datetime("$year $start_date")
->epoch();
my $end_epoch = $date_parser->parse_datetime("$year $end_date")
->add( days => 1 )
->epoch(); # Add one to get next day
my $parser = DateTime::Format::Strptime->new(
pattern => '%Y %b %d %T', # YYYY Mon DD HH:MM:SS
);
print "Start Epoch : $start_epoch [ $start_date ]n";
print "End Epoch : $end_epoch [ $end_date ]n";
for my $log_date ('May 27 09:33:33',
'Jun 05 09:33:33',
'Jun 10 09:33:33',
'Jun 20 09:33:33',
'Jun 30 09:33:33',) {
my $epoch = $parser->parse_datetime("$year $log_date")->epoch();
print "Log Epoch : $epoch [ $log_date ]n";
if ( $start_epoch <= $epoch and $epoch < $end_epoch) {
# Less than end_epoch (midnight) to match previous day
print "==> Log Epoch is in rangen";
}
}
输出如下内容:
Start Epoch : 1433894400 [ June 10 ]
End Epoch : 1434844800 [ June 20 ]
Log Epoch : 1432719213 [ May 27 09:33:33 ]
Log Epoch : 1433496813 [ Jun 05 09:33:33 ]
Log Epoch : 1433928813 [ Jun 10 09:33:33 ]
==> Log Epoch is in range
Log Epoch : 1434792813 [ Jun 20 09:33:33 ]
==> Log Epoch is in range
Log Epoch : 1435656813 [ Jun 30 09:33:33 ]
在不使用核心库的情况下计算历元日期是不明智的,因为现在您将需要担心自unix出生日期(1970年1月1日)以来的天数、闰日、闰秒,并且您将有如此多的边缘情况试图破坏您的乐趣。有很多方法会导致这个错误。但是还有一个选择:
如果出于某种原因,您反对使用核心库模块,您可以通过将日期转换为规范形式,然后只选择范围内的日期来搜索日志文件。
下面是相同的示例,但没有使用任何模块,而是使用规范化(规范)日期代替:
#!/usr/bin/env perl
use strict;
use warnings;
my %months = ( jan => 1, feb => 2, mar => 3, apr => 4,
may => 5, jun => 6, jul => 7, aug => 8,
sep => 9, oct => 10, nov => 11, dec => 12 );
my $year = 2015; # TODO: what year is it? Need to worry about Dec/Jan rollover
my @log_dates = (
'May 27 09:33:33',
'Jun 05 09:33:33',
'Jun 10 09:33:33',
'Jun 20 09:33:33',
'Jun 30 09:33:33',
);
my $start_date = 'June 10';
my $end_date = 'June 20';
my $start_canonical = canonical_date_for_mmmdd_hhmmss("$year $start_date 00:00:00");
my $end_canonical = canonical_date_for_mmmdd_hhmmss("$year $end_date 23:59:59");
for my $log_date (@log_dates) {
my $canonical_date = canonical_date_for_mmmdd_hhmmss("$year $log_date");
print "Log Canonical Date : $canonical_date [ $log_date ]n";
if ($start_canonical <= $canonical_date and
$canonical_date <= $end_canonical) {
print "===> Date in rangen";
}
}
sub canonical_date_for_mmmdd_hhmmss {
my ($datestr) = @_;
my ($year, $mon, $day, $hr, $min, $sec) =
$datestr =~ m|^(d+)s+(w+)s+(d+)s+(d+):(d+):(d+)$|; # YYYY Month DD HH:MM:SS
$year > 1900
or die "Unable to handle year '$year'";
my $month_first_three = lc( substr($mon,0,3) );
my $month_num = $months{$month_first_three};
defined $month_num
or die "Unable to handle month '$mon'";
(1 <= $day and $day <= 31)
or die "Unable to handle day '$day'";
(0 <= $hr and $hr <= 23)
or die "Unable to handle hour '$hr'";
(0 <= $min and $min <= 59)
or die "Unable to handle minute '$min'";
(0 <= $sec and $sec <= 59)
or die "Unable to handle second '$sec'";
my $fmt = "%04d%02d%02d%02d%02d%02d"; # YYYYMMDDHHMMSS
return sprintf($fmt, $year, $month_num, $day, $hr, $min, $sec);
}
输出如下:
Log Canonical Date : 20150527093333 [ May 27 09:33:33 ]
Log Canonical Date : 20150605093333 [ Jun 05 09:33:33 ]
Log Canonical Date : 20150610093333 [ Jun 10 09:33:33 ]
===> Date in range
Log Canonical Date : 20150620093333 [ Jun 20 09:33:33 ]
===> Date in range
Log Canonical Date : 20150630093333 [ Jun 30 09:33:33 ]
请参见ISO 8601 (数据元素和交换格式)了解使用规范化/规范化时间戳的其他属性。