Perl:如何漂亮打印时差(持续时间)

时间:2012-11-02 16:48:20

标签: perl datetime duration datediff

如何在perl中打印持续时间?

到目前为止我唯一能想到的是

my $interval = 1351521657387 - 1351515910623; # milliseconds
my $duration = DateTime::Duration->new(
    seconds => POSIX::floor($interval/1000) ,
    nanoseconds  => 1000000 * ($interval % 1000),
);
my $df = DateTime::Format::Duration->new(
    pattern => '%Y years, %m months, %e days, ' .
               '%H hours, %M minutes, %S seconds, %N nanoseconds',
    normalize => 1,
);
print $df->format_duration($duration);

导致

0 years, 00 months, 0 days, 01 hours, 35 minutes, 46 seconds, 764000000 nanoseconds

由于以下原因,这对我没有好处:

  1. 我不想看到“ 0年”(空间浪费)& c而且我不想删除“%Y years pattern(如果下次确实需要多年,该怎么办?)
  2. 我事先知道我的精度只有几毫秒,我不想看到纳秒部分的6个零。
  3. 我比关于精度/机器可读性更关心可爱/紧凑/人类可读性。即,我希望看到类似“ 1。2年”或“ 3.22个月”或“ 7.88天”或“ 5.7小时“或” 75.5分钟“(或” 1.26小时“,无论你看起来更好)或” 24.7秒“或“ 133.7毫秒”& c(类似于 R 打印difftime的方式)

3 个答案:

答案 0 :(得分:3)

您可以根据某些值是否为“true”动态构建模式。

...
push @pattern, '%Y years' if $duration->year;
push @pattern, '%m months' if $duration->month;
...
my $df = DateTime::Format::Duration->new(
    pattern => join(', ', @pattern),
    normalize => 1,
);
print $df->format_duration($duration);

答案 1 :(得分:1)

以下是我最终使用的内容:

sub difftime2string ($) {
  my ($x) = @_;
  ($x < 0) and return "-" . difftime2string(-$x);
  ($x < 1) and return sprintf("%.2fms",$x*1000);
  ($x < 100) and return sprintf("%.2fsec",$x);
  ($x < 6000) and return sprintf("%.2fmin",$x/60);
  ($x < 108000) and return sprintf("%.2fhrs",$x/3600);
  ($x < 400*24*3600) and return sprintf("%.2fdays",$x/(24*3600));
  return sprintf("%.2f years",$x/(365.25*24*3600));
}

答案 2 :(得分:0)

  

我希望看到类似“1。2年”或“3.22个月”或“7.88天”

的内容

您可以使用Time::Seconds中的常量:

use Time::Seconds;
use feature qw(say);
...

$time_seconds = $interval / 1000;
if ( $time_seconds > ONE_YEAR ) {
    printf "The interval is %.2f years\n", $time_seconds / ONE_YEAR;
}
else {
if ( $time_seconds > ONE_DAY ) {
    printf "The interval is %.2f days\n", $time_seconds / ONE_DAY;
}
else { 
if ( $time_seconds > ONE_HOUR ) {
    printf "The interval is %.2f hours\n", $time_seconds / ONE_HOUR;
}
else {
    say "The interval is $time_seconds seconds";
}

也可以使用switch,但它仍然标记为 experimental ;

use feature qw(switch say);
use Time::Seconds;

...
my $time_seconds = $interval / 1000;

for ( $time_seconds ) {
    when ( $time_seconds > ONE_YEAR ) {
        printf "The interval is %.2f years\n", $time_seconds / ONE_YEAR;
    }
    when ( $time_seconds > ONE_DAY ) {
        printf "The interval is %.2f days\n", $time_seconds / ONE_DAY;
    }
    when ( $time_seconds > ONE_HOUR ) {
        printf "The interval is %.2f hours\n", $time_seconds / ONE_HOUR;
    }
    default { say "The interval is $time_seconds seconds"; }
}

甚至可能有一种方法可以将所有内容组合到一个数组中,以便拥有一个 Time 语句。 (未经测试,但你明白了):

 my @times = (
    [ INTERVAL => ONE_YEAR, VALUE => "years" ],
    [ INTERVAL => ONE_DAY,  VALUE => "days"  ],
    [ INTERVAL => ONE_HOUR, VALUE => "hours" ],
);

for my $interval ( @times ) {
    if ( $time_seconds > $interval->{INTERVAL} ) {
       printf "The interval is %.2f %s\n"
          , $time_seconds / $interval->{INTERVAL}, $interval->{VALUE};
    }
}

对此并不太疯狂。你最好只需要一个pretty_time子程序来隐藏代码。

say pretty_time( $interval );