use strict;
use warnings;
use 5.016;
use Data::Dumper;
use DateTime::Format::Strptime;
my @lines = (
"2015/01/13 13:54:01.853-05:00 11860 acuser *replica_sync_cmd 7f1f9bfff700 10.101.17.111",
"2015/01/13 13:59:01.854-05:00 11860 acuser replica_sync_cmd 7f1f9bfff700 10.101.17.111",
"2015/01/13 13:55:01.266-05:00 11861 acuser *replica_fetch_cmd 7f1f9bfff700 10.101.17.111",
"2015/01/13 13:58:01.267-05:00 11861 acuser replica_fetch_cmd 7f1f9bfff700 10.101.17.111",
);
my %results;
#Group the start and end times together:
for my $line (@lines) {
my ($date, $time, $id, $user, $cmd) = split " ", $line; #splits on any sequence of contiguous whitespace
if ($cmd =~ s/\A [*]//xms) { #if replaced a '*' at beginning of cmd, then...
$results{$id} = ["$date $time", $user, $cmd];
}
else {
unshift @{$results{$id}}, "$date $time"; #push the datetime onto the front of the array
}
}
say Dumper(\%results);
#Subtract the times within each array:
for my $id (keys %results) {
my $end_str = $results{$id}->[0];
$end_str =~ s/:(\d{2})\z/$1/xms; #replace ':' in timezone
my $start_str = $results{$id}->[1];
$start_str =~ s/:(\d{2})\z/$1/xms; #replace ':' in timezone
#"2015/01/13 13:54:01.853-0500"
my $strp = DateTime::Format::Strptime->new(
pattern => "%Y/%m/%d %H:%M:%S.%3N%z",
on_error => 'croak',
);
my $end_dt = $strp->parse_datetime($end_str);
my $start_dt = $strp->parse_datetime($start_str);
#say ref($end_dt); #=>DateTime
#Do datetime math in the same timezone:
$end_dt->set_time_zone('UTC');
$start_dt->set_time_zone('UTC');
my $dur = $end_dt->subtract_datetime_absolute($start_dt);
say Dumper($dur);
say $dur->seconds; #If you care about nano seconds, you'll have to access
#the nanoseconds in $dur and do some math
}
--output:--
$VAR1 = {
'11861' => [
'2015/01/13 13:58:01.267-05:00',
'2015/01/13 13:55:01.266-05:00',
'acuser',
'replica_fetch_cmd'
],
'11860' => [
'2015/01/13 13:59:01.854-05:00',
'2015/01/13 13:54:01.853-05:00',
'acuser',
'replica_sync_cmd'
]
};
$VAR1 = bless( {
'seconds' => 180,
'minutes' => 0,
'end_of_month' => 'wrap',
'nanoseconds' => 1000000,
'days' => 0,
'months' => 0
}, 'DateTime::Duration' );
180
$VAR1 = bless( {
'seconds' => 300,
'minutes' => 0,
'end_of_month' => 'wrap',
'nanoseconds' => 1000000,
'days' => 0,
'months' => 0
}, 'DateTime::Duration' );
300
全局匹配
...
修饰符 //g 代表全局匹配,允许匹配运算符在一个字符串内尽可能多地匹配。在标量上下文中,对字符串的连续调用将 //g 从匹配项跳转到匹配项,同时跟踪字符串中的位置。
...
在列表上下文中,//g 返回匹配分组的列表,如果没有分组,则返回与整个正则表达式匹配的列表。
http://perldoc.perl.org/perlretut.html#Using-regular-expressions-in-Perl
另见:
日期时间::格式::Strptime
http://search.cpan.org/~drolsky/DateTime-1.18/lib/DateTime.pm#Math_Methods
日期时间
http://search.cpan.org/~drolsky/DateTime-1.18/lib/DateTime.pm#Math_Methods