我需要一些关于我的代码的帮助。我想从"检查开始"中获得最早的时间。列,并从"检查站"获取最新时间。专栏。问题是我的脚本似乎没有正确地拿起最早的时间。或者是否可以使用下面的脚本比较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
答案 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。此模块导入旧的timelocal
和timegm
函数,并附带Perl。 Time:timegm
也会导入timegm
,但Time::Local
是Perl安装的标准,而Time::timegm
则不是。{/ p>
Time::Local
模块导入两个函数:timelocal
和timegm
。这两个函数从列表中获取时间元素并将其转换为自Epoch(通常是1970年1月1日)以来的秒数。这些内容是内置于核心Perl函数集中的旧localtime
和gmtime
函数的反函数。
这四个命令:timegm
,gmtime
,localtime
和timelocal
是在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::Piece。 Time::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;
}
.
.
.