What's an easy way to convert 00:20:40.28
(HH:MM:SS) to seconds with a Bash script?
Split seconds can be cut out, it’s not essential.
What's an easy way to convert 00:20:40.28
(HH:MM:SS) to seconds with a Bash script?
Split seconds can be cut out, it’s not essential.
Try awk
. As a bonus, you can keep the split seconds.
echo "00:20:40.25" | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }'
Try this:
T='00:20:40.28'
SavedIFS="$IFS"
IFS=":."
Time=($T)
Seconds=$((${Time[0]}*3600 + ${Time[1]}*60 + ${Time[2]})).${Time[3]}
IFS="$SavedIFS"
echo $Seconds
($<string>) splits <string> based on the splitter (IFS
).
${<array>[<index>]} returns the element of the <array> at the <index>.
$((<arithmetic expression>)) performs the arithmetic expression.
Hope this helps.
This would work even if you don't specify hours or minutes: echo "04:20:40" | sed -E 's/(.*):(.+):(.+)/\1*3600+\2*60+\3/;s/(.+):(.+)/\1*60+\2/' | bc
If you are processing a time from ps
, mind you that the format 2-18:01
is also possible for 2 days, 19 hours, 1 minute. In that case you'll want to checkout: Parse ps' "etime" output and convert it into seconds
echo "40.25" | awk -F: '{ if (NF == 1) {print $NF} else if (NF == 2) {print $1 * 60 + $2} else if (NF==3) {print $1 * 3600 + $2 * 60 + $3} }'
40.25
echo "10:40.25" | awk -F: '{ if (NF == 1) {print $NF} else if (NF == 2) {print $1 * 60 + $2} else if (NF==3) {print $1 * 3600 + $2 * 60 + $3} }'
640.25
echo "20:10:40.25" | awk -F: '{ if (NF == 1) {print $NF} else if (NF == 2) {print $1 * 60 + $2} else if (NF==3) {print $1 * 3600 + $2 * 60 + $3} }'
72640.25
You can convert minutes to hour, seconds, or minutes with bc
command.
By example:
How many minutes for 1000 sec ?
$ echo 'obase=60;1000' | bc
02 00
then -> 2 min
How much hour for 375 min ?
$ echo 'obase=60;375'| bc
06 15
then -> 06h15
How days for 56 hours?
$ echo 'obase=24;56' | bc
02 08
then 02 days and 08 hours
bc with obase is extra!
With GNU date, you can perform the conversion if the duration is less than 24 hours, by treating it as a time of day on the epoch:
to_seconds() {
local epoch=$(date --utc -d @0 +%F)
date --utc -d "$epoch $1" +%s.%09N
}
Running it with the example from the question:
$ to_seconds 00:20:40.29
1240.290000000
Note that --utc
, @
, %s
and %N
are all GNU extensions not necessarily supported by other implementations.
If you don't know what exactly do you have - SS, MM:SS or HH:MM:SS, like after youtube-dl --get-duration
, then awk magic could be useful:
echo 12 | awk -F\: '{ for(k=NF;k>0;k--) sum+=($k*(60^(NF-k))); print sum }'
12
echo 35:12 | awk -F\: '{ for(k=NF;k>0;k--) sum+=($k*(60^(NF-k))); print sum }'
2112
echo 1:35:12 | awk -F\: '{ for(k=NF;k>0;k--) sum+=($k*(60^(NF-k))); print sum }'
5712
I haven't tested this but, I think this is how you'd split the string. Followed by multiplying by the appropriate amounts for hours and minutes.
mytime=’00:20:40.28′
part1=${mytime%%:*}; rest=${mytime#*:}
part2=${rest%%:*}; rest=${rest#*:}
part3=${rest%%:*};
with the shell,
#!/bin/bash
d="00:20:40.28"
IFS=":"
set -- $d
hr=$(($1*3600))
min=$(($2*60))
sec=${3%.*}
echo "total secs: $((hr+min+sec))"
I have this old shell function (/bin/sh compatible in the sense of POSIX shell, not bash) which does this conversion in integer math (no fractions in the seconds):
tim2sec() {
mult=1
arg="$1"
res=0
while [ ${#arg} -gt 0 ]; do
prev="${arg%:*}"
if [ "$prev" = "$arg" ]; then
curr="${arg#0}" # avoid interpreting as octal
prev=""
else
curr="${arg##*:}"
curr="${curr#0}" # avoid interpreting as octal
fi
curr="${curr%%.*}" # remove any fractional parts
res=$((res+curr*mult))
mult=$((mult*60))
arg="$prev"
done
echo "$res"
}
Outputs:
$ tim2sec 1:23:45.243
5025
It works with SS, MM:SS and HH:MM:SS only :)