我有一个时间间隔(以秒为单位,带小数),我想以人类可读的(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