Perl计算2个时间戳之间的差异

时间:2015-01-15 21:51:06

标签: perl time

我有2个带有以下时间戳的变量,并希望得到它们之间的区别

 my $startdate = "2015/01/13 13:57:02.079-05:00";
 my $enddate ="2015/01/13 13:59:02.079-05:00";

如何实现时差?

4 个答案:

答案 0 :(得分:1)

使用DateTime,它只是

$edt->subtract_datetime_absolute($sdt)->in_units('nanoseconds') / 1e9

剩下的就是生成DateTime对象。为此,DateTime :: Format :: Strptime几乎是完美的。

use DateTime::Format::Strptime qw( );

my $sts = "2015/01/13 13:57:02.079-05:00";
my $ets = "2015/01/13 13:59:02.079-05:00";

my $format = DateTime::Format::Strptime->new(
   pattern  => '%Y/%m/%d %H:%M:%S.%3N%z',
   on_error => 'croak',
);

my $sdt = $format->parse_datetime( $sts =~ s/:(?=\d\d\z)//r );
my $edt = $format->parse_datetime( $ets =~ s/:(?=\d\d\z)//r );

my $diff = $edt->subtract_datetime_absolute($sdt)->in_units('nanoseconds') / 1e9;
printf("%.3f\n", $diff);  # 120.000

如果您希望代码也在早于5.14的Perl版本上运行,请替换

my $sdt = $format->parse_datetime( $sts =~ s/:(?=\d\d\z)//r );
my $edt = $format->parse_datetime( $ets =~ s/:(?=\d\d\z)//r );

s/:(?=\d\d\z)// for $sts, $ets;

my $sdt = $format->parse_datetime($sts);
my $edt = $format->parse_datetime($ets);

答案 1 :(得分:-1)

使用Time::Piece中的strptime()将您的两个日期解析为对象。从另一个中减去一个Time :: Piece对象,它将为您提供一个Time::Seconds对象。

我不会只是给你代码,因为你需要自己付出一点努力。

答案 2 :(得分:-2)

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返回匹配分组的列表,或者如果没有分组,则返回整个正则表达式的匹配列表。
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

答案 3 :(得分:-3)

endend一个例子,有点伪代码...不能按原样工作,而是提出这个想法:

#!/usr/bin/perl

use strict;
use warnings;
use Time::Local;
use DateTime::Format::DateParse;

my $startdate = "2015/01/13 13:57:02.079-05:00";
my $enddate ="2015/01/13 13:59:02.079-05:00";

# PArse into components
my $starttime = DateTime::Format::DateParse->parse_datetime( $startdate );
my $endtime = DateTime::Format::DateParse->parse_datetime( $enddate );

# Convert to epoch time
my $st = timelocal($ssec,$smin,$shours,$sday,$smonth, $syear);
my $et = timelocal($esec,$emin,$ehours,$eday,$emonth, $eyear);

#Do the math
my $diff = $et - $s;

print "Difference is $diff seconds...\n";

希望它有所帮助!!