如何比较Perl中的timegm?

时间:2014-04-14 11:46:49

标签: perl

我需要一些关于我的代码的帮助。我想从"检查开始"中获得最早的时间。列,并从"检查站"获取最新时间。专栏。问题是我的脚本似乎没有正确地拿起最早的时间。或者是否可以使用下面的脚本比较timegm格式

我的数据:

                Inspection Start      Inspection Stop

E4855 WI_LEFT01 3/12/2014_5:00:09_AM 3/12/2014_5:02:08_AM 9334 8195 8135 59 1 60 99.27 
H0096 WI_LEFT01 3/12/2014_5:22:58_AM 3/12/2014_5:24:55_AM 9334 8197 8138 58 1 59 99.28 
L0998 WI_LEFT01 3/12/2014_5:29:13_AM 3/12/2014_5:31:09_AM 9334 8163 8088 73 2 75 99.08 
P0113 WI_LEFT01 3/12/2014_5:15:37_AM 3/12/2014_5:17:39_AM 9334 8008 7927 80 1 81 98.99 
P0149 WI_LEFT01 3/12/2014_5:12:36_AM 3/12/2014_5:14:31_AM 9334 8195 8125 68 2 70 99.15 
T2765 WI_LEFT01 3/12/2014_5:25:59_AM 3/12/2014_5:28:00_AM 9334 7810 7732 77 1 78 99.00 
T5518 WI_LEFT01 3/12/2014_5:04:37_AM 3/12/2014_5:06:37_AM 9334 8182 8107 73 2 75 99.08 

我的代码:

#!/usr/bin/perl 

use Time::timegm; 

my $line = ""; 
my $ins_start_time =""; 
my $ins_end_time =""; 
my $tst_start_time =""; 
my $tst_start_time =""; 

open FH, "<file.txt" or die "could not open file, $!"; 

while($line=<FH>) { 
    chomp($line); 
    $line =~ s/\cM//g; 

    my @dummy = split /\s/, $line; 
    #print "$line\n"; 

    if ($dummy[0] =~ /^[A-Z]\d{0,4}$/i) { 
        ($dump, $dump, $st_dump, $et_dump, @dump) = @dummy; 

        ($mm, $dd, $yy, $hh, $min, $sec, $dump) = split /[\/\_\:]+/, $st_dump; 
        $ins_start_time = timegm($sec, $min, $hh, $dd, $mm-1, $yy); 
        print "$ins_start_time\t"; 

        if ($tst_start_time <= $ins_start_time) { 
            $tst_start_time = $ins_start_time; 
        } 

        ($mm, $dd, $yy, $hh, $min, $sec, $dump) = split /[\/\_\:]+/, $et_dump; 
        $ins_end_time = timegm($sec, $min, $hh, $dd, $mm-1, $yy); 
        print "$ins_end_time\n"; 

        if ($ins_end_time >= $tst_end_time) { 
            $tst_end_time = $ins_end_time; 
        } 
    } 
} 

close FH; 

print "Start Time =$tst_start_time\n"; 
print "Start Time =$tst_end_time\n"; 

OUTPUT: 

Start Time =1394602153 ##---->incorrect 

Start Time =1394602269 

EXPECTED OUTPUT: 

Start Time =1394600409 ##---->correct

Start Time =1394602269 

4 个答案:

答案 0 :(得分:0)

您正在寻找$ins_start_time的最小值?你的问题在这里:

if ($tst_start_time <= $ins_start_time) { ... }

你需要:

if ($ins_start_time < $tst_start_time) { ... }

另外,您忽略了AM / PM(鉴于您的样本集有限,这不是问题,但以后可能会出现问题),并且您确定日期格式为mm/dd/yyyy,不是dd/mm/yyyy

编辑:虽然上述内容将解决您的直接问题,正如其他人所建议的那样,有更优雅,更健壮的方法来解决这个问题。我建立在Dave Cross&#39;溶液:

use strict;
use warnings;
use 5.010;

use Time::Piece;
use List::Util 'max', 'min';

my $fmt = '%m/%d/%Y_%H:%M:%S_%p';

my @times = map Time::Piece->strptime($_, $fmt), map {(split)[2,3]} <DATA>;
say "start = " . min @times;
say "end = "   . max @times;

__DATA__
E4855 WI_LEFT01 3/12/2014_5:00:09_AM 3/12/2014_5:02:08_AM 9334 8195 8135 59 1 60 99.27 
H0096 WI_LEFT01 3/12/2014_5:22:58_AM 3/12/2014_5:24:55_AM 9334 8197 8138 58 1 59 99.28 
L0998 WI_LEFT01 3/12/2014_5:29:13_AM 3/12/2014_5:31:09_AM 9334 8163 8088 73 2 75 99.08 
P0113 WI_LEFT01 3/12/2014_5:15:37_AM 3/12/2014_5:17:39_AM 9334 8008 7927 80 1 81 98.99 
P0149 WI_LEFT01 3/12/2014_5:12:36_AM 3/12/2014_5:14:31_AM 9334 8195 8125 68 2 70 99.15 
T2765 WI_LEFT01 3/12/2014_5:25:59_AM 3/12/2014_5:28:00_AM 9334 7810 7732 77 1 78 99.00 
T5518 WI_LEFT01 3/12/2014_5:04:37_AM 3/12/2014_5:06:37_AM 9334 8182 8107 73 2 75 99.08

答案 1 :(得分:0)

如果您使用Time::Piece之类的内容,这可能会更容易一些。

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;

use Time::Piece;

my $fmt = '%m/%d/%Y_%H:%M:%S_%p';

# Assumes that all of your data will be in the past
my $min_time = localtime;
my $max_time = localtime(0);

while (<DATA>) {
  my ($start_str, $stop_str) = (split)[2,3];
  my $start_time = Time::Piece->strptime($start_str, $fmt);
  my $stop_time  = Time::Piece->strptime($stop_str, $fmt);
  if ($start_time->epoch < $min_time->epoch) {
    $min_time = $start_time;
  }
  if ($stop_time->epoch > $max_time->epoch) {
    $max_time = $stop_time;
  }
}

say 'start - ', $min_time->strftime($fmt);
say 'stop  - ', $max_time->strftime($fmt);

__DATA__
E4855 WI_LEFT01 3/12/2014_5:00:09_AM 3/12/2014_5:02:08_AM 9334 8195 8135 59 1 60 99.27 
H0096 WI_LEFT01 3/12/2014_5:22:58_AM 3/12/2014_5:24:55_AM 9334 8197 8138 58 1 59 99.28 
L0998 WI_LEFT01 3/12/2014_5:29:13_AM 3/12/2014_5:31:09_AM 9334 8163 8088 73 2 75 99.08 
P0113 WI_LEFT01 3/12/2014_5:15:37_AM 3/12/2014_5:17:39_AM 9334 8008 7927 80 1 81 98.99 
P0149 WI_LEFT01 3/12/2014_5:12:36_AM 3/12/2014_5:14:31_AM 9334 8195 8125 68 2 70 99.15 
T2765 WI_LEFT01 3/12/2014_5:25:59_AM 3/12/2014_5:28:00_AM 9334 7810 7732 77 1 78 99.00 
T5518 WI_LEFT01 3/12/2014_5:04:37_AM 3/12/2014_5:06:37_AM 9334 8182 8107 73 2 75 99.08

答案 2 :(得分:0)

使用Time::Local。此模块导入旧的timelocaltimegm函数,并附带Perl。 Time:timegm也会导入timegm,但Time::Local是Perl安装的标准,而Time::timegm则不是。{/ p>

Time::Local模块导入两个函数:timelocaltimegm。这两个函数从列表中获取时间元素并将其转换为自Epoch(通常是1970年1月1日)以来的秒数。这些内容是内置于核心Perl函数集中的旧localtimegmtime函数的反函数。

这四个命令:timegmgmtimelocaltimetimelocal是在Perl中处理日期的非常非常古老的方法。它们来自Perl 3.x并在时间元素列表之间来回转换为 the epoch 之后的秒数(通常,但不是1970年1月1日)。

如您所见,这不是处理日期和时间的最简洁或最简单的方法。例如,月份数字介于0到11之间,而不是1到12之间,小时数为24小时,年份作为自1900年以来的年数处理。这意味着2014年为114.您可以添加1900到了这一年。

看一下来回转换时间的两个子程序,看看有趣。

#!/usr/bin/env perl

use Time::Local;
use warnings;
use strict;
use feature qw(say);

my $earliest_start_time;
my $latest_stop_time;
while ( my $line = <DATA> ) {
    chomp $line;
    my @line_array = split /\s+/, $line;
    my $start_time = $line_array[2];
    my $stop_time   = $line_array[3];
    #
    # Here comes the fun!: We'll make a function for now...
    #
    my $start_epoch_time = convert_time_to_epoch( $start_time );
    my $stop_epoch_time  = convert_time_to_epoch ( $stop_time );
    if ( not defined $earliest_start_time or $start_epoch_time < $earliest_start_time ) {
        $earliest_start_time = $start_epoch_time;
    }
    if ( not defined $latest_stop_time or $stop_epoch_time > $latest_stop_time ) {
        $latest_stop_time = $stop_epoch_time;
    }
}

say 'The earliest time is ' . convert_time_from_epoch( $earliest_start_time );
say 'The latest time is ' . convert_time_from_epoch( $latest_stop_time );

#
# We hid the mess here
#
sub convert_time_to_epoch {
    my $time    = shift; # The time in report format

    #
    # First, we have to parse out the time pieces
    #
    if ( not $time =~ m{(\d+)/(\d+)/(\d+)_(\d+):(\d+):(\d+)_([AP]M)} ) {
        die qq(Invalid time format);
    }
    my $month   = $1;
    my $day     = $2;
    my $year    = $3;
    my $hour    = $4;
    my $minute  = $5;
    my $seconds = $6;
    my $meridian = $7;

    #
    # Now we have to normalize. Hours are 24 hours and month is from 0 - 11. Also year is 1900 + year
    #
    $month = $month - 1;
    $year  = $year - 1900;
    if ( $meridian eq "PM" ) {
        $hour = $hour + 12;
    }
    #
    # Finally, we can convert it to the number of seconds since the Epoch
    #
    return timelocal($seconds, $minute, $hour, $day, $month, $year);
}

sub convert_time_from_epoch {
    my $epoch_time = shift;

    my ( $seconds, $minute, $hour, $day, $month, $year ) = localtime $epoch_time;
    #
    # Normalize again. Month is from 0 to 11. Year adds 1900 to it.
    #
    $month += 1;
    $year += 1900;
    my $meridian;
    if ( $hour <= 12 ) {
        $meridian = "AM";
    }
    else {
        $hour -= 12;
        $meridian = "PM";
    }
    return sprintf "%d/%d/%d_%d:%02d:%02d_%s",
        $month, $day, $year, $hour, $minute, $seconds, $meridian
}

__DATA__
E4855 WI_LEFT01 3/12/2014_5:00:09_AM 3/12/2014_5:02:08_AM 9334 8195 8135 59 1 60 99.27 
H0096 WI_LEFT01 3/12/2014_5:22:58_AM 3/12/2014_5:24:55_AM 9334 8197 8138 58 1 59 99.28 
L0998 WI_LEFT01 3/12/2014_5:29:13_AM 3/12/2014_5:31:09_AM 9334 8163 8088 73 2 75 99.08 
P0113 WI_LEFT01 3/12/2014_5:15:37_AM 3/12/2014_5:17:39_AM 9334 8008 7927 80 1 81 98.99 
P0149 WI_LEFT01 3/12/2014_5:12:36_AM 3/12/2014_5:14:31_AM 9334 8195 8125 68 2 70 99.15 
T2765 WI_LEFT01 3/12/2014_5:25:59_AM 3/12/2014_5:28:00_AM 9334 7810 7732 77 1 78 99.00 
T5518 WI_LEFT01 3/12/2014_5:04:37_AM 3/12/2014_5:06:37_AM 9334 8182 8107 73 2 75 99.08

正如其他人所指出的那样,你应该使用Time::PieceTime::Piece是Perl的标准配置,并且处理日期的方式较为简洁。

答案 3 :(得分:0)

你们似乎都是正确的。我也做了一些研究,发现了这个解决方法或解决方案: 我将var声明更改为:

my $ins_start_time =0; 
my $ins_end_time =0; 
my $tst_start_time =0; 
my $tst_start_time =0x7fffffff;
.
.
.
if ($tst_start_time >= $ins_start_time)
{
     $tst_start_time = $ins_start_time;
}
.
.
.
相关问题