47

I want to do a bash script that measures the launch time of a browser for that I am using an html which gets the time-stamp on-load in milliseconds using JavaScript.

In the shell script just before i call the browser I get the time-stamp with:

date +%s

The problem is that it gets the time-stamp in seconds, and I need it in milliseconds since sometimes when ran a second time the browser starts in under a second and I need to be able to measure that time precisely using milliseconds instead of seconds.

How can I get the time-stamp in milliseconds from a bash script?

5 Answers 5

68

With the GNU or ast-open implementation of date (or busybox' if built with the FEATURE_DATE_NANO option enabled), I would use:

$ date +%s%3N

which returns milliseconds since Unix epoch.

3
  • 2
    Indeed elegant, +1. If like me you want to be sure %3N does the necessary left zero padding (without reading the docs. ;-), you can do while sleep 0.05; do date +%s%3N; done, and yes, the necessary zeros are in there. Aug 8, 2019 at 14:06
  • Thank you Terry! However %3N is indeed zero padded. Furthermore I do not think your solution would add zeroes, just delay the response ever so little. Aug 9, 2019 at 7:36
  • 1
    javabeangrinder, @TerryBrown's code wasn't a solution, just test code to verify that %3N is indeed 0-padded. Nov 22, 2019 at 12:53
39

date +%s.%N will give you, eg., 1364391019.877418748. The %N is the number of nanoseconds elapsed in the current second. Notice it is 9 digits, and by default date will pad this with zeros if it is less than 100000000. This is actually a problem if we want to do math with the number, because bash treats numbers with a leading zero as octal. This padding can be disabled by using a hyphen in the field spec, so:

echo $((`date +%s`*1000+`date +%-N`/1000000))

would naively give you milliseconds since the epoch.

However, as Stephane Chazelas points out in comment below, that's two different date calls which will yield two slightly different times. If the second has rolled over in between them, the calculation will be an entire second off. So:

echo $(($(date +'%s * 1000 + %-N / 1000000')))

Or optimized (thanks to comments below, though this should have been obvious):

echo $(( $(date '+%s%N') / 1000000));
10
  • I tried it and it works, thanks +1/accept! Mar 27, 2013 at 13:38
  • 7
    Note that in between the time you run the first date and the second date, several million nanoseconds may have passed and it might not even be the same second. Best to do $(($(date +'%s * 1000 + %N / 1000000'))). That still doesn't make much sense, but would be more reliable. Mar 27, 2013 at 16:24
  • 1
    Fixed by turning off zero padding as noted in date(1) Mar 27, 2013 at 19:09
  • 4
    %N isn't available in BSD and OS X.
    – orkoden
    Jan 29, 2015 at 11:20
  • 4
    Why not just echo $(( $(date '+%s%N') / 1000000))? Nov 21, 2019 at 22:15
15

In case anyone is using other shells than bash, ksh93 and zsh have a floating point $SECONDS variable if you do a typeset -F SECONDS which can be handy to measure time with accuracy:

$ typeset -F SECONDS=0
$ do-something
something done
$ echo "$SECONDS seconds have elapsed"
18.3994340000 seconds have elapsed

Since version 4.3.13 (2011) zsh has a $EPOCHREALTIME special floating point variable in the zsh/datetime module:

$ zmodload zsh/datetime
$ echo $EPOCHREALTIME
1364401642.2725396156
$ printf '%d\n' $((EPOCHREALTIME*1000))
1364401755993

Note that that's derived from the two integers (for seconds and nanoseconds) returned by clock_gettime(). On most systems, that's more precision than a single C double floating point number can hold, so you'll lose precision when you use it in arithmetic expressions (except for dates in the first few months of 1970).

$ t=$EPOCHREALTIME
$ echo $t $((t))
1568473231.6078064442 1568473231.6078064

To compute high precision time differences (though I doubt you'd need more than millisecond precision), you may want to use the $epochtime special array instead (which contains the seconds and nanoseconds as two separate elements).

Since version 5.7 (2018) the strftime shell builtin also supports a %N nanosecond format à la GNU date and a %. to specify the precision, so the number of milliseconds since the epoch can also be retrieved with:

zmodload zsh/datetime
strftime %s%3. $epochtime

(or stored in a variable with -s var)

1
  • 1
    Note that the variable "$SECONDS" is not connected/related to EPOCH time. The fractional part (milliseconds, microseconds and nanoseconds) may be quite different in each.
    – user232326
    Sep 13, 2019 at 15:26
8

To avoid calculations to get the milliseconds, command line JavaScript interpreters may help:

bash-4.2$ node -e 'console.log(new Date().getTime())' # node.js
1364391220596

bash-4.2$ js60 -e 'print(new Date().getTime())'       # SpiderMonkey
1364391220610

bash-4.2$ jsc -e 'print(new Date().getTime())'        # WebKit 
1364391220622

bash-4.2$ seed -e 'new Date().getTime()'              # GNOME object bridge
1364391220669

Packages containing those interpreters on Ubuntu Eoan:

6

In bash 5+ there is a variable with micro-second granularity: $EPOCHREALTIME.

So:

$ echo "$(( ${EPOCHREALTIME//.} / 1000 ))"
1568385422635

Prints time since epoch (1/1/70) in miliseconds.

Failing that, you must use date. Either the GNU date:

echo "$(date +'%s%3N')"

One of the alternatives listed in https://serverfault.com/a/423642/465827

Or brew install coreutils for OS X

Or, if everything else fails, compile (gcc epochInµsec.c) this c program (adjust as needed):

#include <stdio.h>
#include <sys/time.h>
int main(void)
{
  struct timeval time_now;
    gettimeofday(&time_now,NULL);
    printf ("%ld secs, %ld usecs\n",time_now.tv_sec,time_now.tv_usec);

    return 0;
}

Note that calling any external program needs time to be read and loaded from disk, started, run and finally to print the output. That will take several milliseconds. That is the minimum precision that could be achieved with any external tool (including date).

You must log in to answer this question.

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