在 shell 中格式化並顯示帶有小數秒的間隔

在 shell 中格式化並顯示帶有小數秒的間隔

我有一個時間間隔(以秒為單位,帶小數),我想以人類可讀的(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 的 shell(除了一些古老的 POSIX 之前的 shell)。

答案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表示如果整數是個位數,則用前導 0 填滿該整數。%06.3f最奇怪的是,它的意思是小數點後3位,如果總長度小於6(包括小數點)則用前導0填滿。

故意不帶引號的$(…)替換給出了這三個參數,使用dc

首先,將$seconds(展開後的數字)壓入堆疊;複製它;然後除以(截斷)3600 即可得到小時數。彈出並列印該內容,然後推入空格並列印它 ( [ ] n)。

堆疊上只剩下秒了。複製它,除以 60(再次截斷)。這給了分鐘;採取 mod 60 來丟棄小時數。列印出來,再次加上空格。只在堆疊上留下秒數。

最後,mod 60 只給出秒字段,在直流中,模數非常適合小數並保留精度。f然後列印堆疊加上換行符。

答案3

您可以輕鬆地用簡單的 sh 完成它。您可以使用 GNU date 使程式碼稍微短一些(希望您不介意向下捨入毫秒,四捨五入到最接近的值會稍微長一些):

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

相關內容