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 }'
Share:
10,331

Related videos on Youtube

user328302
Author by

user328302

Updated on September 18, 2022

Comments

  • user328302
    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
    user328302 over 5 years
    Wow, thanks. Would you be willing to add a few quick comments above some of the lines of code that explain what's happening?
  • user000001
    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
    martinw over 2 years
    I know it's old but: Shouldn't it be bc -l in the last line instead of only bc?
  • Haxiel
    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
    martinw over 2 years
    Yes, sorry, you are right. I remebered badly the effect of @-l@.
  • Stéphane Chazelas
    Stéphane Chazelas over 2 years
    Or just do echo "$var1:$var2" | awk -F: ...