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 ( [id://110550]=CUFP: print w/replies, xml ) Need Help??

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"; }

Replies are listed 'Best First'.
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

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (4)
As of 2024-03-19 11:39 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found