シェルの小数秒単位で書式設定と表示間隔

シェルの小数秒単位で書式設定と表示間隔

人間が読める形式(H:MM:SS.SSS)で表示したい時間間隔(小数点を含む秒単位)があります。たとえば、16633.284 は 4:37:13.284 と表示する必要があります。この時間はすべて24時間以内ですが、超過すれば数時間しか過ぎません。

以下はいくつかの追加例です。

   0      → 0:00:00.000
  60.394  → 0:01:00.394
8944.77   → 2:29:04.770

10時間固定幅であることに注意してください。もちろん、これを使用して簡単に実行できますprintf

私は解決策を答えとして投稿していますが、これを行うより良い方法があると思うので質問します。他の方法はありますか?私はbashisms、zshismsなどについて開いています。

注:これは以下に関連しています。秒を日/時/分/秒で表示しますか?しかし、bashの算術は整数でのみ行われるため、これらの方法のいずれも機能しません。

答え1

小数部は時間、分、秒数に影響を与えないため、単に別々に保管しないで計算を実行してから最後に追加するだけです。このような:

#!/bin/sh
seconds=16633.284
f=${seconds##*.}
if [ "$f" = "$seconds" ]; then f=0; fi
t=${seconds%.*}
s=$((t%60))
m=$((t/60%60))
h=$((t/60/60))
printf '%d:%02d:%06.3f\n' $h $m $s.$f

出力:

   0     → 0:00:00.000
  33.    → 0:00:33.000
    .21  → 0:00:00.210
  60.394 → 0:01:00.394
8944.77  → 2:29:04.770

これはshに似たすべてのシェルで動作します(一部の古代POSIX以前のシェルを除く)。

答え2

私の方法は、次のように計算するためにdc使用されます。

seconds=16633.284
printf '%i:%02i:%06.3f\n' \
    $(dc -e "$seconds d 3600 / n [ ] n d 60 / 60 % n [ ] n 60 % f")

printfがおなじみであることを願っていますが、そうでない場合は%i整数を表します。%02i整数が1桁の数字の場合、整数の前に0を付けることを示します。%06.3f最も奇妙なことは、小数点以下の3桁を意味し、全長が6(小数点を含む)より小さい場合、先頭に0が追加されることです。

意図的に引用されていない$(…)置換は、次の3つのパラメータを提供しますdc

まず$seconds(拡張数字)をスタックにプッシュし、3600で割って時間を取得します。それをポップアップして印刷し、スペースを押して印刷します([ ] n)。

スタックには秒だけ残った。コピーして60で割ります(もう一度切り捨て)。時間を捨てるにはモード60が必要です。スペースを再度追加して印刷します。スタックには秒だけ残ります。

最後に、mod 60は秒フィールドのみを提供します。 DCでは、モジュラスは素数に完全で精度を維持します。f次に、スタックと改行文字を印刷します。

答え3

簡単なshで簡単にできます。 GNU日付を使用してコードを少し短くすることができます(ミリ秒単位で丸めても大丈夫です。最も近い値に丸めるとコードが少し長くなります)。

hours=$((${seconds%.*} / 3600))
min_s_nano=$(TZ=GMT date -d @$seconds +%M:%S.%N)
time_string=$hours:${min_s_nano%??????}

答え4

秒を呼び出しdcてスタックに入れ、計算を実行し(秒 - > HH / MM / SS.MSEC)、結果をフォーマットして表示します。

seconds=16633.284

dc <<DC
# rearrange stack for number < 1hr
[r ldx q]sb

# rearrange stack for number < 1min
[rd ldxq]sc

# min++, sec-=60   hrs++, min-=60
[r1+r 60-d 60!>a]sa

# display result as h:mm:ss.sss
[n 58an 2lpx 58an 2lpx 46an 3lpx 10an]sd

# perform the conversion of seconds -> hours, minutes, seconds
[d60 >c lax r0rd60 >b lax r ldx]si

[
d1000* 1000% 1/r   # fractional portion
 1000* 1000/ 1/0r  # integer    portion
lix
]sh

# left zero-pad a number
[lk1+d sk 0n le >g ]sg
[sedZd sk    le >gn]sp

# setup the number on the stack and begin computation
$seconds lhx
DC

結果

0                 -->  0:00:00.000
60.394            -->  0:01:00.394
8944.77           -->  2:29:04.770
86399.99          -->  23:59:59.990
59.9999           -->  0:00:59.999
599.9999          -->  0:09:59.999
16633.284         -->  4:37:13.284
33                -->  0:00:33.000
.21               -->  0:00:00.210
123456789.123456  -->  34293:33:09.123

関連情報