Bash scripting often requires measuring time intervals or capturing timestamps with precision beyond seconds. While the standard date command provides second-level accuracy, obtaining millisecond or even microsecond resolution requires a bit more finesse. This tutorial explores several methods to achieve millisecond precision timestamps within your Bash scripts.
Understanding Time Representation
Before diving into specific commands, it’s helpful to understand how time is typically represented in Unix-like systems. The epoch is a point in time (January 1, 1970, 00:00:00 UTC) and time is often stored as the number of seconds that have elapsed since this epoch. More precise timestamps extend this by including fractional seconds, measured in microseconds or nanoseconds.
Using the date Command
The date command is a versatile tool for manipulating and formatting dates and times. Fortunately, it can be leveraged to obtain millisecond precision, though the specific approach varies slightly depending on your system.
-
Seconds and Nanoseconds: The
%sformat specifier returns the number of seconds since the epoch. The%Nspecifier retrieves nanoseconds. Combining these provides a high-resolution timestamp.date +%s%NThis will output a large integer representing seconds since the epoch, followed by up to nine digits representing nanoseconds. To get milliseconds, you need to divide the nanoseconds by 1,000,000.
-
Extracting Milliseconds with Arithmetic: You can perform the division directly within Bash:
echo $(( ( $(date +%s%N) / 1000000 ) ))This command calculates the number of seconds since the epoch, adds the nanoseconds (converted to milliseconds), and echoes the result. This effectively gives you milliseconds since the epoch.
-
Formatting Milliseconds Directly (with
%3N): Some versions ofdatesupport limiting the number of digits displayed for nanoseconds. Using%3Nwill display only the first three digits of the nanosecond value, effectively giving you milliseconds.date +%s%3NNote that this may not be universally supported.
Example: Measuring Execution Time
Let’s illustrate how to measure the execution time of a command in milliseconds using the date command:
#!/bin/bash
start=$(date +%s%N)
# Your command to measure
sleep 2
end=$(date +%s%N)
duration=$(( (end - start) / 1000000 ))
echo "Execution time: ${duration} milliseconds"
This script captures the timestamp before and after the sleep 2 command, calculates the difference in nanoseconds, and converts it to milliseconds.
Portability Considerations
The %N flag and specific behaviors of date can vary between different Unix-like systems (e.g., Linux, macOS). On macOS, the standard date command might not support %N. In such cases, installing coreutils via a package manager like Homebrew (using brew install coreutils) provides a gdate command that behaves similarly to the Linux date command. You can then alias date to gdate for consistency.
Alternative Approach: Using /proc/uptime
For Linux systems, another method involves reading the /proc/uptime file. This file provides system uptime and idle time in seconds. While less direct, it can be used to measure short intervals:
#!/bin/bash
read up rest </proc/uptime
t1="${up%.*}${up#*.}"; # Extract uptime in seconds with fractional part
sleep 3 # Your command
read up rest </proc/uptime
t2="${up%.*}${up#*.}"; # Extract updated uptime
millisec=$(( 10 * (t2 - t1) ))
echo "$millisec"
This approach avoids reliance on date and may be slightly more efficient for very short timing measurements. However, it is Linux-specific and less portable.
Choosing the Right Method
The best method for obtaining millisecond timestamps depends on your specific needs:
- Portability and General Use: The
date +%s%Napproach, combined with division, is generally the most portable and widely applicable. - Short Timing Measurements (Linux): Using
/proc/uptimecan be more efficient for measuring very short durations on Linux systems. - macOS: If you’re on macOS and need nanosecond precision, install
coreutilsand usegdate.