【问题标题】:Perl calculate difference between 2 timestampsPerl计算2个时间戳之间的差异
【发布时间】:2015-03-14 10:47:08
【问题描述】:

我有 2 个具有以下时间戳的变量,想了解它们之间的差异

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

如何实现时差?

【问题讨论】:

  • How to calculate the difference between two timestamp strings in Perl的可能重复项注意格式略有不同,但原理是一样的。
  • Time::Piece 是否支持 tz 偏移?如果不是,那么这个问题的答案很糟糕。对于更改,支持 DST 更改的所有信息都存在,因此应该使用它!
  • @ikegami 好点。 Time::Piece 确实支持 tz 偏移,但前提是小时和分钟之间没有分隔符,例如-0500。此外,它不支持小数秒,因此不能用于此特定问题。撤回我的近距离投票。
  • @ThisSuitIsBlackNot,对于:,使用 s/// 轻松删除

标签: perl time


【解决方案1】:
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

【讨论】:

    【解决方案2】:

    使用 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);
    

    【讨论】:

      【解决方案3】:

      使用来自Time::Piecestrptime() 将您的两个日期解析为对象。从另一个中减去一个 Time::Piece 对象,得到一个 Time::Seconds 对象。

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

      【讨论】:

        【解决方案4】:

        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";
        

        希望对你有帮助!!

        【讨论】:

        • DateTime::Format::DateParse 不支持该格式,如果您已经有 DateTime 对象,则使用 Time::Local 没有意义。
        猜你喜欢
        • 2013-05-21
        • 1970-01-01
        • 2020-05-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多