I was curious how DateTime::Precise did things and noticed it uses Math::BigFloat. But 60*60*60*10000 fits in 32 unsigned bits, so you really need 33 since you are taking differences. But that will fit easily in the 52-odd bits of a C double so you can use regular Perl numbers for this and have perfect accuracy.
The trick is to only use integer values (if you don't want to convince yourself that the round-off of fractional values won't bight you, which they probably wouldn't in this case anyway):
#!/usr/bin/perl -w
use strict;
sub time2num {
my $time= shift(@_);
my( $hr, $min, $sec, $dec )= split /[:.]/, $time;
$dec= substr( $dec."0000", 0, 4 );
return $dec + 10000*($sec+60*($min+60*$hr));
}
sub num2time {
my $tick= shift(@_);
my $sign= '+';
if( $tick < 0 ) {
$sign= '-';
$tick= -$tick;
}
my $sec= int( $tick/10000 );
$tick %= 10000;
my $min= int( $sec/60 );
$sec %= 60;
my $hr= int( $min/60 );
$min %= 60;
return sprintf "%s%d:%02d:%02d.%04d",
$sign, $hr, $min, $sec, $tick;
}
my $diff= time2num('16:14:13.8167')
- time2num('16:23:14.6152');
printf "%.4f\n", $diff/10000;
printf "%s\n", num2time($diff);
prints
-540.7985
-0:09:00.7985
- tye |