3

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)?

Polar Bear
  • 6,762
  • 1
  • 5
  • 12
  • So you don't have a date at all, just time? Indeed, what if it crosses into another day? How do you tell whether it's morning or evening? Can it be multiple days? – zdim Sep 13 '22 at 05:50
  • Perhaps what you are looking for is answered in [Q95492](https://stackoverflow.com/questions/95492/how-do-i-convert-a-date-time-to-epoch-time-unix-time-seconds-since-1970-in-per). As it was indicated you need not just time but a complete date. – Polar Bear Sep 13 '22 at 06:03
  • No date.. the log seems to go from 0 to 24 and then revert back to 0. I can put a constraint on not crossing multiple days but I have to cover 24 hours. If someone kicks of the run overnight and then in the morning they will expect an email with run stats. – Public Email Sep 13 '22 at 12:53

2 Answers2

3

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 
clamp
  • 2,552
  • 1
  • 6
  • 16
  • I copied your code and ran and I am still seeing that difference is 0. I printed out the variables $tp_st and $tp_e and here are their values $tp_st = Thu Jan 1 00:00:00 1970 – Public Email Sep 13 '22 at 16:31
  • I tried this : ( another answer I found on the website) my $str1 = 'Execution started at 05/25/2011 05:22:03 PM'; my $str2 = 'Execution completed at 05/25/2011 05:34:08 PM'; my @times = map Time::Piece->strptime(/(\d.+M)/, '%m/%d/%Y %H:%M:%S %p'), $str1, $str2; my $delta = $times[1] - $times[0]; The problem here is that this code doesnt work if Hours are represented as 24 hr format and if PM/AM arent present. I tried removing %p from the equation but that just didnt compile – Public Email Sep 13 '22 at 16:49
  • I don't believe you copied my code. Did you add `use strict; use warnings;` ? Did you remove the `my` from both your `if` -statenments? – clamp Sep 13 '22 at 16:59
  • I copied it on a separate file word to word.... and executed it! I am not sure why my $tp_st = Time::Piece->strptime($start_time,'%H:%M:%S'); is giving back Thu Jan 1 00:00:00 1970 – Public Email Sep 13 '22 at 17:15
  • Check what you have in `$start_time` before calling `strptime()` – clamp Sep 13 '22 at 17:26
  • It works now!. Sorry, $start_time had a typo that I passed through command line and it didnt work well with the match command. Thanks again for your help – Public Email Sep 13 '22 at 17:39
2

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.

zdim
  • 64,580
  • 5
  • 52
  • 81
  • The issue is that this string Time::Piece->strptime($time, "%H:%M:%S") gives back Thu Jan 1 00:00:00 1970 – Public Email Sep 13 '22 at 17:12
  • @PublicEmail Did you actually run this? It's a copy-pasted program. I added a command and its output – zdim Sep 13 '22 at 17:13
  • @PublicEmail Explanation: What you get out of `Time::Piece->strptime` is a `Time::Piece` _object_, and if you print that it gets "stringified" into what you quote. But, when you subtract two such objects then it does the job and returns seconds between them. – zdim Sep 13 '22 at 17:20
  • The issue in on my end. Other peers have suggested solutions and I cant reproduce. Nevertheless, I want to thank you for you help. I apologize if my remark sounded anything but sincere. – Public Email Sep 13 '22 at 17:23
  • @PublicEmail That's OK, please do make remarks :) But then can you not run it? It doesn't use/do anything special? I edited, with a function to convert secs to hh:mm:ss (just a user convenience) I'll edit for commentary. All that I show as "prints..." comes directly copied from my terminal, from a program copied verbatim from what is posted. – zdim Sep 13 '22 at 17:27
  • @PublicEmail "_The issue in on my end. ... I cant reproduce_" -- what Perl version do you have, what system are you running on? – zdim Sep 13 '22 at 17:34
  • It works! The issue was in the command line that I was passing. – Public Email Sep 13 '22 at 17:40
  • @PublicEmail OK! :) I edited further ... – zdim Sep 13 '22 at 17:41
  • @PublicEmail Completed edits. Let me know if there are questions – zdim Sep 13 '22 at 17:49