Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Formatting elapsed time

by grinder (Bishop)
on Sep 06, 2001 at 16:37 UTC ( #110550=snippet: print w/ replies, xml ) Need Help??

Description:

The following snippet turns a number of seconds to a compact string representing the equivalent amount of seconds in weeks, days, hours, minutes and seconds. This is useful for reporting elapsed time in an easily-graspable human-readable format (just how many weeks or days 123 456 789 seconds anyway)?

Here are some examples

1212s
601m0s
36001h0m0s
36011h0m1s
36611h1m1s
108003h0m0s
864011d0h0m1s
123456789204w0d21h33m9s

The code has a rather pleasing symmetry.

sub wdhms {
    my( $weeks, $days, $hours, $minutes, $seconds, $sign, $res ) = qw/
+0 0 0 0 0/;

    $seconds = shift;
    $sign    = $seconds == abs $seconds ? '' : '-';
    $seconds = abs $seconds;

    ($seconds, $minutes) = ($seconds % 60, int($seconds / 60)) if $sec
+onds;
    ($minutes, $hours  ) = ($minutes % 60, int($minutes / 60)) if $min
+utes;
    ($hours,   $days   ) = ($hours   % 24, int($hours   / 24)) if $hou
+rs;
    ($days,    $weeks  ) = ($days    %  7, int($days    /  7)) if $day
+s;

    $res = sprintf '%ds',     $seconds;
    $res = sprintf "%dm$res", $minutes if $minutes or $hours or $days 
+or $weeks;
    $res = sprintf "%dh$res", $hours   if             $hours or $days 
+or $weeks;
    $res = sprintf "%dd$res", $days    if                       $days 
+or $weeks;
    $res = sprintf "%dw$res", $weeks   if                             
+   $weeks;

    return "$sign$res";
}
Comment on Formatting elapsed time
Download Code
Re: Formatting elapsed time
by Hofmator (Curate) on Sep 06, 2001 at 17:34 UTC

    Am I overlooking something or could your sprintf statements be written much simpler like this?

    $res .= sprintf "%dw", $weeks if $weeks; $res .= sprintf "%dd", $days if $days; $res .= sprintf "%dh", $hours if $hours; $res .= sprintf "%dm", $minutes if $minutes; $res .= sprintf '%ds', $seconds;

    Update: That was changed a little bit too much, as grinder correctly remarked ... nevertheless, my main concern were those ugly string interpolations, and I think this works:

    $res .= sprintf "%dw", $weeks if $we +eks; $res .= sprintf "%dd", $days if $days or $we +eks; $res .= sprintf "%dh", $hours if $hours or $days or $we +eks; $res .= sprintf "%dm", $minutes if $minutes or $hours or $days or $we +eks; $res .= sprintf '%ds', $seconds;

    -- Hofmator

      Yes they could, but it would change the behaviour of the routine. For instance, 86401 would produce 1d1s instead of 1d0h0m1s.

      Which may be what you want (ultra-compact!), but it wasn't what I needed.

      update: re your update: you're quite right. Adding the $res into the format string is a bit too clever by half. I completely overlooked .= . It's feedback like this that make Perl Monks such a useful site.

      --
      g r i n d e r
Re: Formatting elapsed time
by m-rau (Scribe) on Feb 10, 2005 at 17:48 UTC
    The following code is a bit more complex. Sorry. But it produced output reflecting the amount of seconds. If something runs short, it says 3 seconds. If something takes longer, it says 1 hour, 3 seconds. If it takes even longer, the script can say 1 year, 3 monhts, 12 weeks, 4 days, 1 hour, 3 minutes, 20 seconds.
    The code is implemented as a runtime tracker.
    #!/usr/bin/perl my $t0; BEGIN { $t0 = time; } END { my $d = time() - $t0; my @int = ( [ 'second', 1 ], [ 'minute', 60 ], [ 'hour', 60*60 ], [ 'day', 60*60*24 ], [ 'week', 60*60*24*7 ], [ 'month', 60*60*24*30.5 ], [ 'year', 60*60*24*30.5*12 ] ); my $i = $#int; my @r; while ( ($i>=0) && ($d) ) { if ($d / $int[$i] -> [1] >= 1) { push @r, sprintf "%d %s%s", $d / $int[$i] -> [1], $int[$i]->[0], ( sprintf "%d", $d / $int[$i] -> [1] ) > 1 ? 's' : ''; } $d %= $int[$i] -> [1]; $i--; } my $runtime = join ", ", @r if @r; warn sprintf "RUNTIME %s\n", $runtime; } my $runTime = rand( 10 ); printf "Runtime is %d\n", $runTime; sleep( $runTime );
      Well, hopefully it takes those 12 weeks and changes that into 2 more months :-)

      As a very minor nit, the definitions of year and month may need to be adjusted depending on just how precise one wants to be. There are several definitions/equivalencies for the exact length of a year located here.

      For example, using the current Sidereal year's approximation as 365.2564, a month is more accurately said to be 365.2564/12 or 30.438 rather than 30.5, and a year based on 30.5 * 12 is 366 days long...

      -Scott

Back to Snippets Section

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: snippet [id://110550]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (3)
As of 2015-07-03 22:48 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (57 votes), past polls