dbrock has asked for the wisdom of the Perl Monks concerning the following question:

Hello...

I have a question to ask about figuring elapsed time... I am writing a script to read log files of a backup software package...

The log files that I am parsing through are ASCII text files... I have extracted the information that I need, and have produced the

output that I desired... Last week I used this knowledge base forum and received many helpful replies... I have found a glitch in my

logic... I thought that I had figured out how to show the elapsed time of a backup job (start and end time extracted from the log files

I mentioned earlier)... My script is quite long so I cannot post the whole thing... Today I went back to paper and tried to go through

the logic of what I wanted to accomplish... As I started to figure out how to track elapsed time when a backup job runs past midnight

and into the next day (my end time would be smaller than my starttime) ... Then, I found a new whole in the logic... How to transverse a

month end... when the condition will exist that my start date is less than my end date... There is also the condition that will exist when

I have a month end job that crosses midnight... (I convert to total seconds of elapsed time)

Here is a example of what I have so far:

%months = qw(January 01 February 02 March 03 April 04 May 05 June 06 J +uly 07 August 08 September 09 October 10 November 11 December 12); # start if ($logfile[$i] =~ /\bJob started:/) { chomp ($tempstring = $logfile[$i]); #datetemp[0] --> Mo +nth $tempstring =~ s/Job started: //; #datetemp[1] --> Da +y $tempstring =~ s/\w*, //; #datetemp[2] --> Ye +ar $tempstring =~ s/,//; #datetemp[3] --> Ho +ur (converted to 24) $tempstring =~ s/:/ /; #datetemp[4] --> Mi +nute : Seconds $tempstring =~ s/at //; #datetemp[5] --> AM + / PM @datetemp = split (/ /, $tempstring); $datetemp[0] = $months{$datetemp[0]}; if ($datetemp[5] eq "PM") { $datetemp[3] = $datetemp[3] + 12;} if ($datetemp[5] eq "AM") { if ($datetemp[3] eq 12) { $datetemp[3] = 0;}} $start = $datetemp[2] . "/" . $datetemp[0] . "/" . $datetemp[1] . " " . $datetemp[3] . ":" . $datetemp[4]; $stime = ($datetemp[3] * 60) + $datetemp[4] ; # <-- convert +to minutes } # I could use: $stime = ($datetemp[3] * 360) + ($datetemp[4] * + 60) # <-- convert to seconds # end if ($logfile[$i] =~ /\bJob ended:/) { chomp ($tempstring = $logfile[$i]); $tempstring =~ s/Job ended: //; $tempstring =~ s/\w*, //; $tempstring =~ s/,//; $tempstring =~ s/:/ /; $tempstring =~ s/at //; @datetemp = split (/ /, $tempstring); $datetemp[0] = $months{$datetemp[0]}; if ($datetemp[5] eq "PM") { $datetemp[3] = $datetemp[3] + 1 +2;} if ($datetemp[5] eq "AM") { if ($datetemp[3] eq 12) { $datetemp[3] = 0;}} $end = $datetemp[2] . "/" . $datetemp[0] . "/" . $datetemp[1] . " " . $datetemp[3] . ":" . $datetemp[4]; $etime = ($datetemp[3] * 60) + $datetemp[4]; # <-- convert + to minutes } # I could use: $stime = ($datetemp[3] * 360) + ($datetemp[4] + * 60) # <-- convert to seconds # time of job in seconds $sectime = ($etime - $stime) * 60; # <-- convert to seconds # sectime = ($etime - $stime) #if already in seconds

The problem is that it's not complete and it does not work... I I'm having trouble developing the logic behind...

I put together $start and $end from parsing the logfile now I need some help with the logic of elapsing the time...

If anyone can help me out please let me know... I can try and clarify this incomplete thought listed above...

Darrick...

dbrock05@comcast.net

udpate (broquaint): re-formatted code and added <code> tags in appropriate places.
update 2 (broquaint): added <readmore> tag

Replies are listed 'Best First'.
Re: Elapsed date and time
by greenFox (Vicar) on Mar 04, 2003 at 05:55 UTC

    Work in epoch seconds and all your problems go away.

    See Time::Local and localtime() for converting to/from epoch seconds.

    --
    Life is a tale told by an idiot -- full of sound and fury, signifying nothing. William Shakespeare, Macbeth

Re: Elapsed date and time
by J9 (Beadle) on Mar 04, 2003 at 06:07 UTC
    Just a thought.. have you tried converting your start time and end time to epoc seconds using Time::Local? This is un tested code..
    use Time::Local; # Second - Min - Hour - Day - Month - Year my $starttime = timelocal($seconds, $mins, $hours, $day, $month, $year +);
    You could so the same with end time and subtract them..

    Something like ...
    $starttime = 1031079733; $endtime = 1013104442; $diff = $starttime - $endtime; print "there is $diff secconds between the 2\n"; $sec = $diff % 60; $diff = ($diff - $sec) / 60; $min = $diff % 60; $diff = ($diff - $min) / 60; $hrs = $diff % 24; $diff = ($diff - $hrs) / 24; $day = $diff % 7; $diff = ($diff - $day) / 7; $week = $diff % 4; $diff = ($diff - $week) / 4; $mnt = $diff % 12; $diff = ($diff - $mnt); $year = $diff; print "\n\nDifferencre is $year Years $mnt Months $week Weeks $day Day +s, $hrs Hours, $min Minutes and $sec Seconds\n";
    Any more expreienced monks to fix the above code would be appreciated.

    Regards
    Janine
      Oh yes, Time::Local::timelocal() was what i was looking for at the time of my reply!
Re: Elapsed date and time
by parv (Parson) on Mar 04, 2003 at 06:34 UTC

    It would help immensely (to help you) if you post some sample data that you are trying to parse, and not create a HTML paragraph every one-and-a-half sentences.

    By the way, there are 3600 seconds in an hour not 360, unless your comment has a typo...

    ... } # I could use: $stime = ($datetemp[3] * 360) + ($datetemp[4] +* 60) # <-- convert to seconds ...

    And since you are repeating the algorithm to generate $stime and $etime, why not create a sub so that you do not have to repeat the same 9-12 lines.

    As to your problem, cause is obvious. You are using only the the hours, minutes (and seconds); you NEED to consider the day-of-the-month, month, and year. To calculate elasped time properly, you need to, for start and end time,...

    1. extract all five (six) date/time values
    2. convert them to the appropriate lowest unit of time measurement
    3. take the difference as you are already doing


    ...you can either create your own algorithm (which i prefer for myself) or use module(s)...

Re: Elapsed date and time
by BrowserUk (Patriarch) on Mar 04, 2003 at 10:43 UTC

    Date/time manipulations--formatting, calculating deltas etc--is one case where I would definitely advocate not rolling your own. I mostly use Date::Manip (although it is, in the authors words, probably the slowest of the Date/Time modules) and despite the fact that the pod itself needs pod. I beleive Date::Calc is nearly as flexible and a lot faster.

    An example of using Date:Manip might help you decide. The following shows the script itself and using it to get the delta between two dates in seconds, minutes, hours, days and weeks.

    C:\test>type datemanip.pl #! perl -slw use strict; use Date::Manip; print Delta_Format( DateCalc( ParseDate($ARGV[0]), ParseDate($ARGV[1]) ) , 0, $ARGV[2]||'%dh' ); C:\test>datemanip " 2/28/2000 11:57:29 PM" " 3/1/2000 1:40:03 pm" %st 135754.000000 C:\test>datemanip " 2/28/2000 11:57:29 PM" " 3/1/2000 1:40:03 pm" %mt 2262.566667 C:\test>datemanip " 2/28/2000 11:57:29 PM" " 3/1/2000 1:40:03 pm" %ht 37.709444 C:\test>datemanip " 2/28/2000 11:57:29 PM" " 3/1/2000 1:40:03 pm" %dt 1.571227 C:\test>datemanip " 2/28/2000 11:57:29 PM" " 3/1/2000 1:40:03 pm" %wt 0.224461

    Examine what is said, not who speaks.
    1) When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong.
    2) The only way of discovering the limits of the possible is to venture a little way past them into the impossible
    3) Any sufficiently advanced technology is indistinguishable from magic.
    Arthur C. Clarke.
Re: Elapsed date and time
by l2kashe (Deacon) on Mar 04, 2003 at 08:57 UTC
    Ok I spent way too much time on this, but I couldn't sleep without figuring this out. It needs to be patched to use BigInt so that it can deal with time lengths over I think 300 days or so, but it tests right, so here it is.. This could probably be cleaned up some as well, but like I said its 4am localtime, and I just couldnt sleep without resolving this...
    # Assume the following values $start = 'Dec 1 2003 4 00:00 AM'; $end = 'Jan 2 2004 5 00:00 AM'; ($s_seconds, $s_year) = parse($start); ($e_seconds, $e_year) = parse($end); if ($s_seconds < $e_seconds) { $elapsed = $e_seconds - $s_seconds; } else { # # we must have rolled over to a new year so... # Grab the remaining seconds in the old year + the seconds in the new +year # $elapsed = $e_seconds + ( $s_year - $s_seconds ); } $days = (split(/\./, $elapsed / 86400))[0]; $rem = $elapsed - (86400 * $days); $hours = (split(/\./, $rem / 3600))[0]; $rem -= 3600 * $hours; $mins = (split(/\./, $rem / 60))[0]; $seconds = $rem - ($mins * 60); print "Total time was: $days Days $hours Hrs $mins Mins $seconds Secs\ +n"; sub parse { my($line) = shift; my($mth,$day,$year,$hour,$tosplit,$arg) = split(/\s+/, $line); my($min, $sec) = split(/:/, $tosplit); # Add 12 if we are in the PM if ($arg =~ /PM/) { $hour += 12; # Set hour to 0 if its 12 AM } elsif ($hour == 12) { $hour = 0; } my($base, $total) = this_year($mth, $year); # beginning of the month + base == # of secs since beginning of year my($return) = $base + $sec + ($min * 60) + ($hour * 3600) + ($day * + 86400); return($return, $total); } sub this_year { my($mth,$year,$thirty,$thirtyo,$tofind,$base,$total, %months); ($mth, $year) = @_; # number of seconds in a month with thirty days and thirty one days $thirty = "2592000"; $thirtyo = "2678400"; %months = ( Jan => [1, $thirtyo ], Feb => [2, '2419200'], Mar => [3, $thirty +o], Apr => [4, $thirty ], May => [5, $thirtyo ], Jun => [6, $thirty +], Jul => [7, $thirtyo ], Aug => [8, $thirtyo ], Sep => [9, $thirty +], Oct => [10, $thirtyo], Nov => [11, $thirty ], Dec => [12, $thirt +yo] ); # Stupid calendar system :P # Man its way to late to be computing leap years.. stupid stupid syste +m if (($year % 4) == 0) { $months{Feb}->[1] += '86400'; if ( ($year % 100) == 0 && ($year % 400) != 0 ) { $months{Feb}->[1] -= '86400'; } } $tofind = $months{$mth}->[0]; for ( sort { $months{$a}->[0] <=> $months{$b}->[0] } keys %months ) + { $base += $months{$_}->[1] if ($tofind >= $months{$_}->[0]); $total += $months{$_}->[1]; } return($base,$total); }
    This prints out
    Total time was: 32 Days 1 Hrs 0 Mins 0 Secs


    /* And the Creator, against his better judgement, wrote man.c */
      It needs to be patched to use BigInt so that it can deal with time lengths over I think 300 days or so

      Not sure where you got that from: a 31-bit integer will hold enough seconds for about 68 years, which is why most Unix-oriented code (with the epoch starting at Jan 1, 1970) can only handle dates up to Jan 19, 2038.

      Hugo
        You know what.. you're right... When I was doing testing though, the same algorithm that worked for smaller values got truncated when I tried to compute lengths greater than 1 year. Since it was so early, I just thought I was running out of space in the 'int', and this morning I was thinking about using an array to store the value, but you're right I shouldn't need to.. I'll have to dig in and see if I can figure out whats going on.

        /* And the Creator, against his better judgement, wrote man.c */
Re: Elapsed date and time
by dbrock (Sexton) on Mar 04, 2003 at 16:11 UTC

    Thank you all,
        I was having my morning coffee and was thinking about this... I was going to try a whole new approach... Converting to EPOCH... If at the earliest point I could convert to seconds... The math would just be a simple subtract...

        I was going to put these loop into a sub but I was just trying to understand first... I guess more than just placing the code in a script, I need to understand exactly what it's doing (For my own piece of mind)...

    You guy are very helpful... Hopefully I can offer you guys some help in the future... Thanks...

    Darrick...