I normally use the DateTime family of modules for this kind of thing. It looks like what you have there are not absolute times, but timer durations, in which case you could try working with DateTime::Duration objects. (If you are instead working with absolute times, see here and here for solutions.)
I looked into how to parse durations, and found DateTime::Format::Duration, but am having trouble getting it to parse milliseconds - I have a suspicion this may be a bug, and will look into this and update my node when I know more (Update: Bug reported.). Until then, parsing the duration manually seems to work, as follows. By the way, is it a typo that your milliseconds in $first only have two digits?
Update 2018-01-15: I have to withdraw my suggestion for DateTime::Format::Duration for now, the number of unfixed bugs - including the one reported by Cristoforo in the reply - is leading me to believe that the module is currently suffering from too many issues to be "just used". See my reply below for a quick-n-dirty alternative, although unfortunately that doesn't support normalization.
use warnings;
use strict;
use DateTime::Duration;
use DateTime::Format::Duration;
my $first = "00:00:01:04";
my $last = "00:00:08:861";
sub my_parse_duration {
my $in = shift;
my %t; @t{qw/hours minutes seconds nanoseconds/}
= $in=~/\A(\d\d):(\d\d):(\d\d):(\d\d\d?)\z/
or die "failed to parse '$in'";
$t{nanoseconds}*=1000000; # ms->ns
return DateTime::Duration->new(%t);
}
$first = my_parse_duration($first);
$last = my_parse_duration($last );
my $fmt_out = DateTime::Format::Duration->new(
pattern=>'%H:%M:%S:%3N', normalize=>1 );
print $fmt_out->format_duration($first),"\n";
print $fmt_out->format_duration($last ),"\n";
$last->subtract_duration($first);
print $fmt_out->format_duration($last ),"\n";
__END__
00:00:01:004
00:00:08:861
00:00:07:857