How to sum time using bash?

16,125

Solution 1

#!/bin/sh

EPOCH='jan 1 1970'
sum=0

for i in 00:03:34 00:00:35 00:12:34
do
  sum="$(date -u -d "$EPOCH $i" +%s) + $sum"
done
echo $sum|bc

date -u -d "jan 1 1970" +%s gives 0. So date -u -d "jan 1 1970 00:03:34" +%s gives 214 secs.

Solution 2

Update:

Here is a new implementation that makes use of dc's "output base." Note that if the total sum is more than 60 hours, this will output four space-separated values instead of three. (And if the total sum is less than one hour, only two space-separated values will be output.)

awk '{print $2}' file.txt | tr : \ | dc -f - -e '60o0ddd[+r60*+r60d**+z1<a]dsaxp'

Input is assumed to be in triples of hour, minute, second, as shown in the question.

Output on the provided input is:

 16 43

Original answer:

Let's do this with dc your Desk Calculator. It's the back-end to bc, and it's extremely flexible although often considered cryptic.


First, some pre-processing to give the times only, and convert the colons to spaces:

awk '{print $2}' | tr : ' '

We could also do this with Sed:

sed -En -e 's/^.*([0-9][0-9]):([0-9][0-9]):([0-9][0-9]).*$/\1 \2 \3/p'

I'll go with Awk and tr because it's simpler. Either of the above command produces a clean output in the following format. (I'm using my own example text because I consider it more interesting; it has hours included. Yours will work as well.)

$ cat input
9 39 42
8 04 50
7 49 32
10 01 54
7 19 18

Given times in the above format, run them through the following Sed script and pipe the result into dc as shown:

sed -e '1s/^/0 /' -e 's/$/ r 60 * + r 60 60 * * + +/' -e '$s/$/ 60 60 * ~ 60 ~ f/' input | dc

(Broken down to reduce sideways scrolling:)

sed <input \
    -e '1s/^/0 /' \
    -e 's/$/ r 60 * + r 60 60 * * + +/' \
    -e '$s/$/ 60 60 * ~ 60 ~ f/' |
      dc 

The output will be seconds, minutes, hours, in that sequence. (Note this is a reversed sequence.) I'm just learning dc so this isn't a perfect solution, but I think it's pretty good for a first look at dc.

Example input and output, pasted directly from my terminal:

$ cat input 
9 39 42
8 04 50
7 49 32
10 01 54
7 19 18
$ sed -e '1s/^/0 /' -e 's/$/ r 60 * + r 60 60 * * + +/' -e '$s/$/ 60 60 * ~ 60 ~ f/' input | dc 
16
55
42
$ 

Solution 3

If you cannot (or don't want) use TIMEFORMAT your just need to transfer time into seconds, then add it together. For example pipe output through:

{                                           
sum=0
while IFS="[ :]" proc_name h m s
do
    let sum+=$((60*($m+60*$h)+$s)) 
done 
echo $sum  
} 

Or if you'd like can exchange last echo-command by

printf "%02d:%02d:%02d\n" $[sum/3600] $[sum/60] $[sum%60]

Solution 4

Assuming you are using the bash 'time' builtin command, before you run your program, you can export TIMEFORMAT=%0R. The output will then be in whole seconds addable by awk. More information is available in the 'Shell Variables' section of the bash man page.

Solution 5

Here is my solution - use split(). Printing total time in seconds:

awk '{
        split($2, tm, ":");
        tottm += tm[3] + tm[2] * 60 + tm[1] * 3600;
    }
    END {
        print tottm;
    }' ptime

Printing in nice time format:

awk '{
        split($2, tm, ":");
        secs += tm[3]; 
        mins += tm[2] + int(secs / 60); 
        hrs += tm[1] + int(mins / 60);
        secs %= 60; mins %= 60;
    }
    END {
        printf "%d:%d:%d\n", hrs, mins, secs;
    }' ptime

GNU awk also supports strftime, but it will use your current timezone, so results would be confusing.

Share:
16,125

Related videos on Youtube

je_b
Author by

je_b

Updated on September 18, 2022

Comments

  • je_b
    je_b almost 2 years

    I want to know the total amount of time that a series of processes would take in my computer to decide if I should running there or in a stronger computer. So, i am forecasting the running time of each command. The output looks like:

    process1    00:03:34
    process2    00:00:35
    process3    00:12:34
    

    How can I sum the second column to obtain a total running time? I could try pipping each line through

    awk '{sum += $2 } END { print sum }
    

    but this makes no sense as the values are not natural numbers.

  • androidism
    androidism over 9 years
    Does seem a little hack-y, but hey, it works in an interesting (sort-of) way.
  • Stéphane Chazelas
    Stéphane Chazelas over 7 years
    You can call gawk with TZ=UTC0 gawk... to remove the timezone issue.
  • Jesse Chisholm
    Jesse Chisholm over 4 years
    The minutes should be $[sum/60%60] to strip the hours off.