Search code examples
perltimeformatmilliseconds

Perl : calculation of time in format hh:mm:ss,sss


I need to calculate the time difference between these two variables in Perl :

my $end = "17:23:31,576";
my $start = "17:23:30,858";

How do I calculate the time difference ($end - $start) ? It's important the the returned value keeps the same format.

I would prefer, ideally, to do that with a native function

I've already tried packages like Time::Piece; and DateTime::Format::Strptime; but couldn't make it work.


Solution

  • A DateTime solution, since it has native support for fractional seconds. Once you got the two DateTime objects, you can use the following program:

    # delta_ms loses nanoseconds, but we need it to convert days into hours.
    my ($h, $m, $s) = $dt2->delta_ms($dt1)->in_units(qw( hours minutes seconds ));
    my $ns = ( $dt2 - $dt1 )->nanoseconds;
    
    say sprintf '%d:%02d:%02d,%03.0f', $h, $m, $s, $ns/1_000_000;
    

    Now, let's look at how to get the two DateTime objects. Given the information provided, the best you can do is the following:

    use DateTime::Format::Strptime qw( );
    
    my $format = DateTime::Format::Strptime->new(
       pattern   => '%H:%M:%S,%3N',
       time_zone => 'floating',
       on_error  => 'croak',
    );
    
    my $dt1 = $format->parse_datetime('01:59:58,123');
    my $dt2 = $format->parse_datetime('03:01:02,456');
    

    Like all other solutions, this won't always give the right answer because the difference can depend on the date and time zone (e.g. due to DST changes), and this information wasn't made available.

    If you do have the information available, then you'd use the following, which correctly gives 1:01:04,333 instead of 0:01:04,333 on the day DST starts.

    use DateTime::Format::Strptime qw( );
    
    my $format = DateTime::Format::Strptime->new(
       pattern   => '%Y-%m-%d %H:%M:%S,%3N',
       time_zone => 'America/New_York',  # Often: 'local'
       on_error  => 'croak',
    );
    
    my $dt1 = $format->parse_datetime('2015-03-09 01:59:58,000');
    my $dt2 = $format->parse_datetime('2015-03-09 03:01:02,000');