Parsing time stamps and calculating difference

Viewed 102

So I am parsing a log file and look for certain time stamps and then subtracting them to get time elapsed.

So I tried a simple code to see if I can use Time::Piece but wasnt successful. My code below:

use Time::Piece;

my ($S, $E);

GetOptions (
    "S=s" => \$S,
    "E=s" => \$E,
    );

my $start    = $S;
my $end = $E;
my %build_time;

my $start_time;
my $end_time;
if(my ($start_time) = $start =~ /\[gg\s+(\d+\:\d+\:\d+)\s+I\]/){
    print"Build_Time: start at $start_time\n";
}
#--------------------
# End time from dj
if(my ($end_time) = $end =~ /\[gg\s+(\d+\:\d+\:\d+)\s+I\]/){
    print "Build_Time: end at $end_time\n";
}

my $difference = Time::Piece->strptime($end_time,'%H:%M:%S') - Time::Piece->strptime($start_time,'%H:%M:%S');

print " difference: $difference \n";

Execute: perl time.pl -S "[gg 8:11:03 I]: Copyright" -E "[gg 8:19:03 I]: BT_DEPTH=99 "

Build_Time: start at 8:11:03 Build_Time: end at 8:19:03 difference: 0

Also what is the time is in 24 hr format and log contains over night run ( so the difference would be negative)?

2 Answers

Your code has a scoping issue: $start_time and $end_time in your if statements mask the outer variables. If the time difference is 23:59:59 max you can use a modulo operation to fix the negative seconds output caused by crossing a date boundary:

time.pl:

use strict;
use warnings;
use Getopt::Long;

use Time::Piece;
my ($S, $E);

GetOptions (
    "S=s" => \$S,
    "E=s" => \$E,
    );

my $start    = $S;
my $end = $E;
my %build_time;

my $start_time;
my $end_time;
if( ($start_time) = $start =~ /\[gg\s+(\d+\:\d+\:\d+)\s+I\]/){
    print"Build_Time: start at $start_time\n";
}
#--------------------
# End time from dj
if( ($end_time) = $end =~ /\[gg\s+(\d+\:\d+\:\d+)\s+I\]/){
    print "Build_Time: end at $end_time\n";
}

my $tp_st = Time::Piece->strptime($start_time,'%H:%M:%S');
my $tp_e =  Time::Piece->strptime($end_time,'%H:%M:%S');

my $difference = $tp_e -$tp_st;
$difference %= 60*60*24; # 1 day
print " difference: $difference \n";

testing:

perl time.pl -S "[gg 8:19:04 I]: Copyright" -E "[gg 8:19:14 I]: BT_DEPTH=99 "
Build_Time: start at 8:19:04
Build_Time: end at 8:19:14
 difference: 10 


perl time.pl -S "[gg 8:19:04 I]: Copyright" -E "[gg 8:19:03 I]: BT_DEPTH=99 "
Build_Time: start at 8:19:04
Build_Time: end at 8:19:03
 difference: 86399 

If input is indeed limited to times within 24 hours then if start time is larger than end time it means it rolled into another day. So you can substract Time::Piece objects and adjust if negative

use warnings;
use strict;
use feature 'say';

use Getopt::Long;
use Time::Piece;

GetOptions ( "S=s" => \my $S, "E=s" => \my $E );

my ($tp_beg, $tp_end) = map { 
    my ($time) = /\[gg\s+ ([0-9]+:[0-9]+:[0-9]+) \s+ I\]/x;
    die "Unexpected input format ($_)" if not $time;
    Time::Piece->strptime($time, "%H:%M:%S")
} $S, $E;

my $diff_secs = $tp_end - $tp_beg;
$diff_secs += 24*60*60  if $diff_secs < 0;

say "Difference is $diff_secs secs";

say "Difference is ", sec_in_day_to_hms($diff_secs);

sub sec_in_day_to_hms {  # add ($tt >= 3600*24) branch for multiple days
    my ($tt) = @_;
    my $msg = do {
        if ( $tt >= 3600 ) {
            sprintf("%d:%02d:%02d (hr:min:sec)",
                $tt/3600, ($tt%3600)/60, $tt%60);
        }
        elsif ( $tt >= 60 ) {
            sprintf("%d min %d sec", ($tt%3600)/60, $tt%60);
        } 
        else { sprintf("%d sec", $tt%60); }
    };
    return $msg;
}

Running as in the question

perl time_diff.pl -S "[gg 8:11:03 I]: Copyright" -E "[gg 8:19:03 I]: BT_DEPTH=99 "

prints

Difference is 480 secs
Difference is 8 min 0 sec

If we change 8:19:03 to 6:19:03 (so it rolled all the way by about two hours short of a full day) and run it as

perl time_diff.pl -S "[gg 8:11:03 I]: Copyright" -E "[gg 6:19:03 I]: BT_DEPTH=99 "

then it prints

Difference is 79680 secs
Difference is 22:08:00 (hr:min:sec)

A comment on the code in the question

It firstly has a mistake of defining a variable $start_time also inside an if block

if(my ($start_time) = $start =~ /.../){

and that variable masks (shadows) the one with the same name declared earlier. After the if block is exited, the earlier $start_time is restored, um, to undef.

When that's used later in the program (for subtraction) it would print warnings -- if you had them on! Please add

use strict;
use warnings;

to the top of every program. These are directly helpful.

One simple way to fix that would be to just remove that my -- then the regex's return is assigned indeed to the earlier declared $start_time. However, I find that there are too many variables introduced for the purpose so I'd suggest to simplify instead.

Then, the possibly negative difference isn't handled, what the question itself asserts.

Related