4

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 years " (スペースの浪費) を見たくない &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を出力する方法と同様)
4

3 に答える 3

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);
于 2012-11-02T16:58:12.563 に答える
2

これが私が最終的に使用したものです:

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));
}
于 2013-11-12T15:12:39.723 に答える
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";
}

スイッチも使用できますが、まだ実験的なものとしてマークされています

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 );
于 2013-11-12T15:34:15.633 に答える