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
12 | 12s |
60 | 1m0s |
3600 | 1h0m0s |
3601 | 1h0m1s |
3661 | 1h1m1s |
10800 | 3h0m0s |
86401 | 1d0h0m1s |
123456789 | 204w0d21h33m9s |
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";
}
Re: Formatting elapsed time
by Hofmator (Curate) on Sep 06, 2001 at 17:34 UTC
|
$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
| [reply] [d/l] [select] |
|
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
| [reply] |
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 );
| [reply] [d/l] |
|
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
| [reply] |
|
|