我需要在Perl中计算这两个变量之间的时差:
my $end = "17:23:31,576";
my $start = "17:23:30,858";
如何计算时差($end - $start
)?重要的是返回的值保持相同的格式。
理想情况下,我希望使用本机功能
我已经尝试了Time::Piece;
和DateTime::Format::Strptime
等软件包;但是无法使它发挥作用。
答案 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;