2012-11-02 74 views
2

如何在Perl中打印持續時間?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年」(space waste)& ca nd我不想從pattern刪除「%Y年」(如果我下次需要幾年呢?)
  2. 我事先知道我的精度只有毫秒,我不想看到納秒中的6個零。
  3. 我關心漂亮/緊湊/人類的可讀性遠遠超過精度/機器的可讀性。也就是說,我希望看到類似「1.2年」或「3.22個月」或「7.88天」或「5.7小時」或「75.5分鐘」(或「1.26小時,無論看起來不如你)或 「24.7秒」 或 「133.7毫秒」 & C(類似於如何[R打印difftime
+0

時間/持續時間的標準國際格式爲'0y 4m 7d 1h 35m 46.764s',即每個組件單元的單字符後綴。 –

+0

那麼我該如何製作呢?爲什麼這不是默認? – sds

回答

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); 
+0

這隻能解決我的第一個抱怨 – sds

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)); 
} 
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"; 
} 

A switch也可以使用,但它仍然標記爲實驗;

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"; } 
} 

甚至有可能是爲了有一個時間聲明一切組合成一個陣列的方式。 (未經測試,但你明白了):

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