# How to measure elapsed time in bash

Last updated on March 9, 2021 by Dan Nanni

Elapsed time is the amount of wall-clock time that has passed between the beginning and the end of a particular event. In other words, elapsed time is a measurement of actual time taken for the event to complete. It is common to to measure elapsed time as part of application performance analysis and profiling. While you are working on a bash script, you may also want to add instrumentation in your script to calculate elapsed time for various components (e.g., a bash function, an external command, etc). In this tutorial, let's find out how to measure elapsed time in a bash script.

The most common way to measure elapsed time in bash is to utilize the `date` command, which can show the current system date and time in a configurable format. Using the flexiblity of `date`'s display format, you can easily calculate elapsed time with different resolutions.

## Measure Elapsed Time in Seconds in Bash

When you call `date` with `+%s` option, it shows the current system clock in seconds since 1970-01-01 00:00:00 UTC. Thus, with this option, you can easily calculate time difference in seconds between two clock measurements.

```start_time=\$(date +%s)
# perform a task
end_time=\$(date +%s)

# elapsed time with second resolution
elapsed=\$(( end_time - start_time ))
```

Another (preferred) way to measure elapsed time in seconds in bash is to use a built-in bash variable called `SECONDS`. When you access `SECONDS` variable in a bash shell, it returns the number of seconds that have passed so far since the current shell was launched. Since this method does not require running the external `date` command in a subshell, it is a more elegant solution.

```start_time=\$SECONDS
sleep 5
elapsed=\$(( SECONDS - start_time ))
echo \$elapsed
```

This will display elapsed time in terms of the number of seconds. If you want a more human-readable format, you can convert `\$elapsed` output as follows.

```eval "echo Elapsed time: \$(date -ud "@\$elapsed" +'\$((%s/3600/24)) days %H hr %M min %S sec')"
```

This will produce output like the following.

```Elapsed time: 0 days 13 hr 53 min 20 sec
```

## Measure Elapsed Time in Milliseconds in Bash

To measure elapsed time with millisecond resolution, use `date` with `+%s.%3N` option, which returns the current time in milliseconds. Since bash does not support floating point arithmetic, you need to rely on an external calculator tool such as `bc` to compute time difference with millisecond resolution. The `bc` calculator allows you to specify the precision of floating point numbers (i.e., number of digits after floating point) with `scale` variable. Thus, with `scale=3`, `bc` computes time difference with millisecond resolution.

```start_time=\$(date +%s.%3N)
# perform a task
end_time=\$(date +%s.%3N)

# elapsed time with millisecond resolution
# keep three digits after floating point.
elapsed=\$(echo "scale=3; \$end_time - \$start_time" | bc)
```

## Measure Elapsed Time in Microseconds or in Nanoseconds in Bash

Technically it is possible to calculate elpased time with a higher resolution such as microsecond-level or nanosecond-level using `date` command, since `date` can show current time in nanosecond resolution. However, such high-resolution elapsed time measurements with `date` command will not be anywhere near accurate due to the variable cost of invoking the external `date` command in a subshell.

As a simple illustration, let's run the following bash script to measure elapsed time of noop (i.e., do nothing) with microsecond resolution.

```while : ; do
start_time=\$(date +%s.%6N)
: # do nothing
end_time=\$(date +%s.%6N)

elapsed=\$(echo "scale=6; \$end_time - \$start_time" | bc)
echo \$elapsed
done
```
```.002829
.002890
.002664
.002456
.002395
.002451
.002397
.002401
.002373
.002449
.002457
.002475
.002753
.002357
.002420
.002442
.002451
.002449
```

As you can see above, elapsed time for the same operation (i.e., do nothing) does not remain constant on microsecond-level. This proves that any sub-milliseond-level elapsed time measurement based on an external command will be highly misleading.

If you know of any trick that can improve the accuracy of elapsed time measurement in bash, feel free to share it in the comment.

## Support Xmodulo

This website is made possible by minimal ads and your gracious donation via PayPal (Credit Card) or Bitcoin (`1M161JGAkz3oaHNvTiPFjNYkeABox8rb4g`).

Please note that this article is published by Xmodulo.com under a Creative Commons Attribution-ShareAlike 3.0 Unported License. If you would like to use the whole or any part of this article, you need to cite this web page at Xmodulo.com as the original source.

Xmodulo © 2021 ‒ AboutWrite for Us ‒ Feed ‒ Powered by DigitalOcean
{"ft_lang_label":"__label__en","ft_lang_prob":0.858135,"math_prob":0.8274115,"size":4521,"snap":"2021-04-2021-17","text_gpt3_token_len":1062,"char_repetition_ratio":0.14633606,"word_repetition_ratio":0.020920502,"special_character_ratio":0.25326255,"punctuation_ratio":0.12142857,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.9561972,"pos_list":[0],"im_url_duplicate_count":[null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2021-04-10T15:04:12Z\",\"WARC-Record-ID\":\"<urn:uuid:fb9190d8-e242-4463-8f28-7ecbcbaf2301>\",\"Content-Length\":\"11610\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:4e992e78-2e67-4b9d-82ad-80be2e5f19c6>\",\"WARC-Concurrent-To\":\"<urn:uuid:2ca019d8-1c2f-4462-8f18-0e689c2800d4>\",\"WARC-IP-Address\":\"172.67.177.60\",\"WARC-Target-URI\":\"https://www.xmodulo.com/measure-elapsed-time-bash.html\",\"WARC-Payload-Digest\":\"sha1:FUBJAKX5KYKVZGX5DXIWCES3LHMKWVP6\",\"WARC-Block-Digest\":\"sha1:VFRVKQVWNOOHMLIG5FFEC2MG4K36WEW5\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2021/CC-MAIN-2021-17/CC-MAIN-2021-17_segments_1618038057142.4_warc_CC-MAIN-20210410134715-20210410164715-00154.warc.gz\"}"}