40

I would like to do the following at one point in a script:

start_time=date

and this after a process or processes have run:

end_time=date

and then do this:

elapsed=$end_time-$start_time
echo "Total of $elapsed seconds elapsed for process"

How would I do this?

3

5 Answers 5

47

Use the time since epoch to easily identify a span of time in a script

man date
%s     seconds since 1970-01-01 00:00:00 UTC
%N     nanoseconds (000000000..999999999)

.

start_time="$(date -u +%s)"
sleep 5
end_time="$(date -u +%s)"

elapsed="$(($end_time-$start_time))"
echo "Total of $elapsed seconds elapsed for process"

 Total of 5 seconds elapsed for process

Bash doesn't support floating point numbers, so you'll need to use a external tool like bc to compare times like 1475705058.042270582-1475705053.040524971

start_time="$(date -u +%s.%N)"
sleep 5
end_time="$(date -u +%s.%N)"

elapsed="$(bc <<<"$end_time-$start_time")"
echo "Total of $elapsed seconds elapsed for process"

 Total of 5.001884264 seconds elapsed for process
4
  • this is what I was looking for.. can this include microtime? Commented Oct 5, 2016 at 20:38
  • Try date '+%s.%N'
    – Miati
    Commented Oct 5, 2016 at 20:58
  • You should call date with date -u to avoid DST and local problems with the command. Please read this answer
    – user232326
    Commented Oct 6, 2016 at 2:16
  • 2
    Seeing as how (traditionally) bc is implemented with dc, you can use dc directly: elapsed=$(dc -e "$end_time $start_time - p") Commented Oct 17, 2018 at 18:57
36

bash has a builtin timer variable

start=$SECONDS
# do stuff
end=$SECONDS
duration=$(( end - start ))
echo "stuff took $duration seconds to complete"
2
  • 5
    Or SECONDS=0; ...; echo "$SECONDS". Beware of that bug though. Commented Oct 5, 2016 at 22:23
  • Alternatively, if you want to have the EPOCH seconds, use echo $EPOCHSECONDS Commented Aug 22, 2022 at 20:31
12

@jasonwryan already suggested it, but I'll throw it in as an answer as it is also my go-to when I want to time a script. To time myscript simply use:

time myscript
2
  • 2
    I will try this from time to time but this is more for when I need to isolate or time sub-sections of my script.. Commented Oct 5, 2016 at 20:38
  • 1
    This is not useful if you want to use the derived elapsed time within the script itself, e.g. to calculate how many units the script was able to process per second. Commented Jul 13, 2020 at 10:25
1

I like @Miata's answer because it draws attention to date +%s solution. However, @Miata includes .%N but I am not sure what benefit you will get looking at nanoseconds when there is the cost of executing the date command in a subshell. So, in practice, date +%s should be sufficient. The other thing to note is date +%s epoch is 1970-01-01 00:00:00 UTC. Which means the time has an absolute epoch and you can share the time measurement between different instances of shell script or different machines.

(( start=$(date +%s) )) # 1604026743
# ... some activity that lasts for, say, 24 seconds
(( end=$(date -u +%s) )) # 1604026767
(( duration=end-start )) # 24

I like @glenn jackman's answer because it refers to SECONDS bash built-in variable. The thing to note here is the epoch is the time when the process was started. So, we can only use this technique to measure times for things that happen within that script:

(( start=SECONDS )) # 10
# ... some activity that lasts for, say, 24 seconds
(( end=SECONDS )) # 34
(( duration=end-start )) # 24

Another thing is I put all my assignments within the (( )) command. i.e. you can rewrite:

cmd=$(( some_expression ))

as

(( cmd=some_expression ))

By doing this, we can minimize the occurrence of the $ symbol.

1

It's terribly annoying to read the answers in terms of seconds, when you're measuring something that might take a long time. You really want to get the answer format right (as hh:mm:ss) without contorted calculations. Use date own functionality, like this:

# Using differences, and give result in hh:mm:ss
S=0; E=121; TT=$((E-S)); date -u -d "@${TT}" +%T
# 00:02:01

# Using date differences, and give result in hh:mm:ss
S=$(date -u +"%s"); E=$((S+121)); TT=$((E-S)); date -u -d "@${TT}" +%T
# 00:02:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .