Subtract time using bash?
10,331
Solution 1
The date
command is pretty flexible about its input. You can use that to your advantage:
#!/bin/bash
var1="23:30"
var2="20:00"
# Convert to epoch time and calculate difference.
difference=$(( $(date -d "$var1" "+%s") - $(date -d "$var2" "+%s") ))
# Divide the difference by 3600 to calculate hours.
echo "scale=2 ; $difference/3600" | bc
Output:
$ ./test.bash
3.50
Solution 2
Using only bash
, with no external programs, you could do so something like this:
#!/bin/bash
# first time is the first argument, or 23:30
var1=${1:-23:30}
# second time is the second argument, or 20:00
var2=${2:-20:00}
# Split variables on `:` and insert pieces into arrays
IFS=':' read -r -a t1 <<< "$var1"
IFS=':' read -r -a t2 <<< "$var2"
# strip leading zeros (so it's not interpreted as octal
t1=("${t1[@]##0}")
t2=("${t2[@]##0}")
# check if the first time is before the second one
if (( t1[0] > t2[0] || ( t1[0] == t2[0] && t1[1] > t2[1]) ))
then
# if the minutes on the first time are less than the ones on the second time
if (( t1[1] < t2[1] ))
then
# add 60 minutes to time 1
(( t1[1] += 60 ))
# and subtract an hour
(( t1[0] -- ))
fi
# now subtract the hours and the minutes
echo $((t1[0] -t2[0] )):$((t1[1] - t2[1]))
# to get a decimal result, multiply the minutes by 100 and divide by 60
echo $((t1[0] -t2[0] )).$(((t1[1] - t2[1])*100/60))
else
echo "Time 1 should be after time 2" 2>&1
fi
Test:
$ ./script.sh
3:30
3.50
$ ./script.sh 12:10 11:30
0:40
0.66
$ ./script.sh 12:00 11:30
0:30
0.50
If you want more complex time differences, that could span different days etc, then it's probably best to use GNU date.
Solution 3
With Awk you can set the separator to be a space or a colon to effectuate the calculations needed:
#!/bin/bash
var1="23:30"
var2="20:00"
echo "$var1" "$var2" | awk -F":| " '{print (60*($1-$3)+($2-$4))/60 }'
Related videos on Youtube
Author by
user328302
Updated on September 18, 2022Comments
-
user328302 almost 2 years
Is it possible to use bash to subtract variables containing 24-hour time?
#!/bin/bash var1="23:30" # 11:30pm var2="20:00" # 08:00pm echo "$(expr $var1 - $var2)"
Running it produces the following error.
./test expr: non-integer argument
I need the output to appear in decimal form, for example:
./test 3.5
-
user328302 over 5 yearsWow, thanks. Would you be willing to add a few quick comments above some of the lines of code that explain what's happening?
-
user000001 over 5 years@user328302: I added some comments, let me know if anything is still unclear. I also fixed a bug that wouldn't allow times like
09:08
(it was treated as octal) -
martinw over 2 yearsI know it's old but: Shouldn't it be
bc -l
in the last line instead of onlybc
? -
Haxiel over 2 years@martinw According to the manpage,
-l
changes the default scale from zero to 20 and also loads a set of math library functions. I'm explicitly setting the scale here, and I'm not using any of the math library functions. So in this scenario,-l
makes no difference in the output. -
martinw over 2 yearsYes, sorry, you are right. I remebered badly the effect of @-l@.
-
Stéphane Chazelas over 2 yearsOr just do
echo "$var1:$var2" | awk -F: ...