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
%s
format specifier returns the number of seconds since the epoch. The%N
specifier retrieves nanoseconds. Combining these provides a high-resolution timestamp.date +%s%N
This 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 ofdate
support limiting the number of digits displayed for nanoseconds. Using%3N
will display only the first three digits of the nanosecond value, effectively giving you milliseconds.date +%s%3N
Note 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%N
approach, combined with division, is generally the most portable and widely applicable. - Short Timing Measurements (Linux): Using
/proc/uptime
can be more efficient for measuring very short durations on Linux systems. - macOS: If you’re on macOS and need nanosecond precision, install
coreutils
and usegdate
.