Perl:以hh:mm:ss,sss格式计算时间

时间:2014-12-30 17:57:57

标签: perl time format milliseconds

我需要在Perl中计算这两个变量之间的时差:

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

如何计算时差($end - $start)?重要的是返回的值保持相同的格式。

理想情况下,我希望使用本机功能

我已经尝试了Time::Piece;DateTime::Format::Strptime等软件包;但是无法使它发挥作用。

3 个答案:

答案 0 :(得分:5)

DateTime解决方案,因为它具有小数秒的原生支持。获得两个DateTime对象后,可以使用以下程序:

# 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;

现在,让我们看一下如何获取两个DateTime对象。根据提供的信息,您可以做的最好的事情如下:

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');

与所有其他解决方案一样,这不会给出正确答案,因为差异可能取决于日期和时区(例如,由于DST更改),并且此信息无法使用。

如果您确实掌握了相关信息,那么您可以使用以下内容,在DST开始的当天正确提供1:01:04,333代替0:01:04,333

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');

答案 1 :(得分:1)

使用Time :: Piece,我认为你必须分别处理毫秒。

use Time::Piece;
my $start = "17:23:31,576";
my $end = "17:23:30,858";
my ($start_time,$start_ms) = split /,/, $start;
my ($end_time,$end_ms) = split /,/, $end;
my $difference = Time::Piece->strptime($end_time,'%H:%M:%S') - Time::Piece->strptime($start_time,'%H:%M:%S') + ( $end_ms - $start_ms ) / 1000;

要将分数秒转回格式化的时间很容易,如果凌乱:

my $negative = $difference < 0 ? '-' : '';
$difference = abs $difference;
my $seconds = int $difference;
my $ms = sprintf '%03d', 1000 * ($difference - $seconds);
my $formatted_difference = Time::Piece->gmtime($seconds)->strftime("$negative%H:%M:%S,$ms");

答案 2 :(得分:1)

只是一种类似但更手动的方法,手动计算差异,并使用gmtime将其分成小时,分钟和秒。手动处理分数,因为gmtime只使用整数。

这有点重塑Time :: Piece,所以我实际上更喜欢ysth的解决方案。

my $start = "17:23:30,858";
my $end   = "17:23:31,576";
#split by ; and ,
my ($h_start,$m_start,$s_start, $frac_start) = split(/[:,]/, $start) ;
my ($h_end,$m_end,$s_end, $frac_end) = split(/[:,]/, $end) ;

#find #seconds since epoch (whatever it is)
my $start_time = $s_start + $m_start * 60 + $h_start * 3600;
my $end_time   = $s_end   + $m_end   * 60 + $h_end   * 3600;
my $diff_sec   = $end_time - $start_time;

#handling fractions independently, paying attention to negative fractions
#0.0 + first to force float
my $diff_frac = 0.0 + "0.$frac_end" - "0.$frac_start";
if ($diff_frac < 0) {
    $diff_frac++;
    $diff_sec--;
}
#then using the build in function to convert from seconds from epoch to sec min hrs
#using gmt (not local) to convert without timezones and daylight savings...
my ($s_diff,$m_diff,$h_diff) = gmtime( $diff_sec);

#and finally manual formatting using sprintf    
my $diff_date = sprintf("%02u:%02u:%02u,%03u", $h_diff,$m_diff,$s_diff,$diff_frac*1000);
print $diff_date;