in reply to Converting seconds to DD:HH:MM:SS

Many thanks for the replies and suggestions.

As an exercise and a follow-up, I decided to throw them all together and see how they stacked up.

(I should point out that this is the first time I've used Benchmark, and also the first time I've attempted to write test code such as this, so my methodology may be a bit off. Also, the only changes I made to the other Monks code snippets was to make them into a subroutine if they weren't already.)

Here is the code I used:
#!/usr/bin/perl -w use strict; use Date::Calc qw(Delta_DHMS Time_to_Date Delta_Days); use Date::Manip; use Benchmark qw(:all); use Data::Dumper::Simple; require "tools.pl"; # Contains connectdb() sub my $dbh = connectdb(); my @secs = qw(-2147483648 -1 0 1 86399 86400 2147483648); my %contenders = ( cw_silly => { code => \&sec_to_dhms_silly }, cw_sensible => { code => \&sec_to_dhms_sensible }, McDarren => { code => \&sec_to_dhms_McDarren }, Tanktalus => { code => \&sec_to_dhms_Tanktalus }, gam3 => { code => \&sec_to_dhms_gam3 }, gloryhack => { code => \&sec_to_dhms_gloryhack }, GrandFather => { code => \&sec_to_dhms_GrandFather }, davidrw => { code => \&sec_to_dhms_davidrw }, snowhare => { code => \&sec_to_dhms_snowhare }, ); for my $s (@secs) { foreach my $c (keys %contenders) { my @res; eval { @res = $contenders{$c}{code}->($s); }; $contenders{$c}{$s} = defined @_ ? "@_" : "@res"; } } print Dumper(%contenders); our $data = 1000; cmpthese -10, { cw_silly => 'my $res = sec_to_dhms_silly($data)', cw_sensible => 'my $res = sec_to_dhms_sensible($data)', McDarren => 'my $res = sec_to_dhms_McDarren($data)', Tanktalus => 'my $res = sec_to_dhms_Tanktalus($data)', gam3 => 'my $res = sec_to_dhms_gam3($data)', gloryhack => 'my $res = sec_to_dhms_gloryhack($data)', GrandFather => 'my $res = sec_to_dhms_GrandFather($data)', davidrw => 'my $res = sec_to_dhms_davidrw($data)', snowhare => 'my $res = sec_to_dhms_snowhare($data)', }; $dbh->disconnect; sub sec_to_dhms_silly { my @epoch = (1970, 1, 1, 0,0,0); my @mytime = gmtime(shift); splice (@mytime, 6); # discard fields after 6th element (yea +r) $mytime[5] += 1900; # gmtime returns year - 1900 $mytime[4]++; # gmtime has zero based month @mytime = reverse @mytime; # Delta_DHMS expects args in reverse to + gmtime return Delta_DHMS(@epoch, @mytime); } sub sec_to_dhms_sensible { shift; my ($d, $h, $m, $s); $s = $_ % 60; $_ = ($_ - $s) / 60; $m = $_ % 60; $_ = ($_ - $m) / 60; $h = $_ % 24; $_ = ($_ - $h) / 24; $d = $_; return ($d, $h, $m, $s); } sub sec_to_dhms_McDarren { my $t = shift; return $dbh->selectrow_array("SELECT sec_to_time($t);"); } sub sec_to_dhms_Tanktalus { use integer; local $_ = shift; my ($d, $h, $m, $s); $s = $_ % 60; $_ /= 60; $m = $_ % 60; $_ /= 60; $h = $_ % 24; $_ /= 24; $d = $_; return ($d, $h, $m, $s); } sub sec_to_dhms_gam3 { my $t = shift; return int($t / 86400), (gmtime($t))[2, 1, 0]; } sub sec_to_dhms_gloryhack { my $t = shift; return sprintf("%s%02d:%02d:%02d:%02d", $t < 0 ? '-' : '', Delta_DHMS(Time_to_Date(0), Time_to_Date(abs($t)))); } sub sec_to_dhms_GrandFather { my $t = shift; my @fields = ($t % 60, ($t /= 60) % 60, ($t /= 60) % 24, int ($t / 24)); return join ':', reverse @fields; } sub sec_to_dhms_davidrw { my $t = shift; return join ":", map { sprintf "%02d", $t } do { my @d = Time_to_Date($t); ( Delta_Days((Time_to_Date(0))[0..2], @d[0..2]), @d[3..5] ) }; } sub sec_to_dhms_snowhare { my $t = shift; return Delta_Format("+${t}seconds",'exact','%dh','%hv','%mv','%sv' +); }
Which gave the following results:
%contenders = ( 'cw_sensible' => { '86399' => '0 0 0 0', '86400' => '0 0 0 0', '1' => '0 0 0 0', '2147483648' => '0 0 0 0', '0' => '0 0 0 0', '-2147483648' => '0 0 0 0', '-1' => '0 0 0 0', 'code' => sub { "DUMMY" } }, 'snowhare' => { '86399' => '0 23 59 59', '86400' => '1 0 0 0', '1' => '0 0 0 1', '2147483648' => '24855 3 14 8', '0' => '0 0 0 0', '-2147483648' => '-24855 -3 -14 -8', '-1' => '0 0 0 -1', 'code' => sub { "DUMMY" } }, 'gam3' => { '86399' => '0 23 59 59', '86400' => '1 0 0 0', '1' => '0 0 0 1', '2147483648' => '24855 20 45 52', '0' => '0 0 0 0', '-2147483648' => '-24855 20 45 52', '-1' => '0 23 59 59', 'code' => sub { "DUMMY" } }, 'gloryhack' => { '86399' => '00:23:59:59', '86400' => '01:00:00:00', '1' => '00:00:00:01', '2147483648' => '', '0' => '00:00:00:00', '-2147483648' => '', '-1' => '-00:00:00:01', 'code' => sub { "DUMMY" } }, 'cw_silly' => { '86399' => '0 23 59 59', '86400' => '1 0 0 0', '1' => '0 0 0 1', '2147483648' => '-24855 -3 -14 -8', '0' => '0 0 0 0', '-2147483648' => '-24855 -3 -14 -8', '-1' => '0 0 0 -1', 'code' => sub { "DUMMY" } }, 'McDarren' => { '86399' => '23:59:59', '86400' => '24:00:00', '1' => '00:00:01', '2147483648' => '596523:14:08', '0' => '00:00:00', '-2147483648' => '-596523:14:08', '-1' => '-00:00:01', 'code' => sub { "DUMMY" } }, 'GrandFather' => { '86399' => '0:23:59:59', '86400' => '1:0:0:0', '1' => '0:0:0:1', '2147483648' => '24855:3:14:8', '0' => '0:0:0:0', '-2147483648' => '-24855:21:46:52', '-1' => '0:0:0:59', 'code' => sub { "DUMMY" } }, 'Tanktulas' => { '86399' => '0 23 59 59', '86400' => '1 0 0 0', '1' => '0 0 0 1', '2147483648' => '-24855 -3 -14 -8', '0' => '0 0 0 0', '-2147483648' => '-24855 -3 -14 -8', '-1' => '0 0 0 -1', 'code' => sub { "DUMMY" } }, 'davidrw' => { '86399' => '86399:86399:86399:86399', '86400' => '86400:86400:86400:86400', '1' => '01:01:01:01', '2147483648' => '', '0' => '00:00:00:00', '-2147483648' => '', '-1' => '', 'code' => sub { "DUMMY" } } ); Rate snowhare McDarren davidrw cw_sensible gloryhack c +w_silly GrandFather gam3 Tanktulas snowhare 510/s -- -83% -97% -98% -99% + -99% -99% -100% -100% McDarren 3040/s 497% -- -84% -86% -91% + -92% -95% -98% -98% davidrw 19472/s 3721% 540% -- -10% -43% + -47% -67% -85% -87% cw_sensible 21611/s 4141% 611% 11% -- -37% + -41% -63% -83% -86% gloryhack 34046/s 6581% 1020% 75% 58% -- + -7% -41% -74% -77% cw_silly 36645/s 7092% 1105% 88% 70% 8% + -- -37% -72% -76% GrandFather 58163/s 11315% 1813% 199% 169% 71% + 59% -- -55% -61% gam3 129947/s 25402% 4174% 567% 501% 282% + 255% 123% -- -14% Tanktulas 150334/s 29403% 4845% 672% 596% 342% + 310% 158% 16% --
Comments

Firstly, [id://snowhare]'s solution throws the following warning:
Argument "exact" isn't numeric in numeric gt (>) at /usr/local/share/p +erl/5.8.4/Date/Manip.pm line 1985.
I'm not sure what causes that, and I'm not inclined right now to go digging in the source of Date::Manip.

Most of the others also threw uninitiallised value warnings when used with '0', but that's to be expected (of course, the DBI solution doesn't have this issue).

Only two of the solutions (interestly, the two slowest) gave correct results for all values of @secs: [id://snowhare]'s and [id://McDarren|my own] (although mine only returns HH:MM:SS - no DD)

A quick summary of each:
Cheers,
--Darren :)

Update:Adjusted <readmore> tags, as suggested by [id://GrandFather]

Replies are listed 'Best First'.
Re^2: Converting seconds to DD:HH:MM:SS
by parv (Parson) on Oct 10, 2005 at 05:41 UTC

    (Initially i was somewhat surprised that Tanktalus's version did not result in the right value for 2^31. I think it may be for you might not have perl compiled w/ USE_64_BIT_INT.)

    A problem in the above benchmark is that not all the subroutines are returning the same type of result. I modified your above code ...

    • removed *_davidrw() from comparison as its result was quite odd;
    • removed *_snowhare() from comparison as it was the slowest (produced the same output as yours) ;
    • removed *_McDarren(), as i do not have mysql or equivalent DB installed currently;
    • edited cmpthese() somewhat;
    • made all the subs to return only a string;
    • grouped (non)module-using subs together.

    Last three versions still place in the same order as in your benchmark, and snowhare version is still the slowest. Big difference is that gloryhack version becomes quite faster than cw_silly, as opposed to gloryhack version being marginally slower in your benchmark.

    Below, comparison is shown, date calculation results hidden ...

    Rate cw_sensible cw_silly gloryhack GrandFather gam3 + Tanktalus cw_sensible 27248/s -- -46% -67% -73% -75% + -83% cw_silly 50161/s 84% -- -40% -49% -55% + -68% gloryhack 83435/s 206% 66% -- -16% -25% + -47% GrandFather 99258/s 264% 98% 19% -- -10% + -37% gam3 110623/s 306% 121% 33% 11% -- + -30% Tanktalus 157554/s 478% 214% 89% 59% 42% + --
Re^2: Converting seconds to DD:HH:MM:SS
by GrandFather (Saint) on Oct 10, 2005 at 02:08 UTC

    Nice summary, though I'd be inclined to only bury the code in the readmore tags. Everything else is likely to be of immediate interest - especially the benchmark results.


    Perl is Huffman encoded by design.