Linux command to get time in milliseconds
Asked Answered
S

17

442

How can I get time in milliseconds in a Bash shell script?

Southerner answered 14/5, 2013 at 16:42 Comment(5)
date +%s.%N would give you nanoseconds, can you work with that?Delocalize
@Delocalize This is not quite portable though.Exemplification
date +"%Y%m%d.%H%M%S%3N" - Generally i use this command to get the fulldate and unique time till milli seconds to create the temporary file names in unix bash script. If your system is not able to cope up milli seconds you can go to micro or nano seconds using 3 to 6 and 9 respectively.Lundquist
Try date -InsTrinatrinal
@CamiloMartin Why is this not portable?Waers
C
459

date +%s%N returns the number of seconds + current nanoseconds.

Therefore, echo $(($(date +%s%N)/1000000)) is what you need.

Example:

$ echo $(($(date +%s%N)/1000000))
1535546718115

date +%s returns the number of seconds since the epoch, if that's useful.

Celestial answered 14/5, 2013 at 17:0 Comment(7)
doesn't work on Mac OS, since %N is not supported by datePoteet
Question is asking for Linux command. @alper's answer works fine for date command with GNU coreutils. GNUtize your OSX: Install and Use GNU Command Line Tools on Mac OS XMateya
date +%s%3N is faster (based in @michael-defort's answer)Mateya
@Mateya I'm not sure... Benchmarking several options in parallel (granted, not TOO strictly) gave me this: pastebin.com/ZFdVWN7h. Frankly, I don't think it makes a difference.Proconsul
On OSX you need to install the GNU version of date as part of coreutils using MacPorts or Homebrew - then use the gdate command. See this question: #9805466Richia
Although date +%s%3N seems to be easier or better, but using it in some other offset calculation caused the timestamp to be reduced by 1 millisecond! But this solution worked perfect with offset calculationMatty
Perhaps something should be said about the actual time resolution? E.g., on a typical PC, will it typically be better than 16.666 ms (1/60 second) or not? Or better than some other (very common) characteristic feature of the underlying hardware?Atheistic
U
545
  • date +"%T.%N" returns the current time with nanoseconds.

    06:46:41.431857000
    
  • date +"%T.%6N" returns the current time with nanoseconds rounded to the first 6 digits, which is microseconds.

    06:47:07.183172
    
  • date +"%T.%3N" returns the current time with nanoseconds rounded to the first 3 digits, which is milliseconds.

    06:47:42.773
    

In general, every field of the date command's format can be given an optional field width.

Undercarriage answered 9/9, 2013 at 17:55 Comment(1)
date +"%Y%m%d.%H%M%S%3N" for milli seconds.Lundquist
C
459

date +%s%N returns the number of seconds + current nanoseconds.

Therefore, echo $(($(date +%s%N)/1000000)) is what you need.

Example:

$ echo $(($(date +%s%N)/1000000))
1535546718115

date +%s returns the number of seconds since the epoch, if that's useful.

Celestial answered 14/5, 2013 at 17:0 Comment(7)
doesn't work on Mac OS, since %N is not supported by datePoteet
Question is asking for Linux command. @alper's answer works fine for date command with GNU coreutils. GNUtize your OSX: Install and Use GNU Command Line Tools on Mac OS XMateya
date +%s%3N is faster (based in @michael-defort's answer)Mateya
@Mateya I'm not sure... Benchmarking several options in parallel (granted, not TOO strictly) gave me this: pastebin.com/ZFdVWN7h. Frankly, I don't think it makes a difference.Proconsul
On OSX you need to install the GNU version of date as part of coreutils using MacPorts or Homebrew - then use the gdate command. See this question: #9805466Richia
Although date +%s%3N seems to be easier or better, but using it in some other offset calculation caused the timestamp to be reduced by 1 millisecond! But this solution worked perfect with offset calculationMatty
Perhaps something should be said about the actual time resolution? E.g., on a typical PC, will it typically be better than 16.666 ms (1/60 second) or not? Or better than some other (very common) characteristic feature of the underlying hardware?Atheistic
T
133

Nano is 10−9 and milli 10−3. Hence, we can use the three first characters of nanoseconds to get the milliseconds:

date +%s%3N

From man date:

%N nanoseconds (000000000..999999999)

%s seconds since 1970-01-01 00:00:00 UTC

Source: Server Fault's How do I get the current Unix time in milliseconds in Bash?.

Trev answered 24/6, 2015 at 7:49 Comment(0)
D
76

On OS X, where date does not support the %N flag, I recommend installing coreutils using Homebrew. This will give you access to a command called gdate that will behave as date does on Linux systems.

brew install coreutils

For a more "native" experience, you can always add this to your .bash_aliases:

alias date='gdate'

Then execute

$ date +%s%N
Dominique answered 10/11, 2015 at 23:21 Comment(1)
This may have changed since this was posted. I don't recall installing coreutils and date +%s%3N works with no issue (Mar 2024).Lawrence
T
30

Here is a portable hack for Linux for getting time in milliseconds:

#!/bin/sh
read up rest </proc/uptime; t1="${up%.*}${up#*.}"
sleep 3    # your command
read up rest </proc/uptime; t2="${up%.*}${up#*.}"

millisec=$(( 10*(t2-t1) ))
echo $millisec

The output is:

3010

This is a very cheap operation, which works with shell internals and procfs.

Tardif answered 13/2, 2018 at 10:53 Comment(1)
I have now idea why I didn't find this sooner. This should be the accepted and perfect answer. I believed for so long there was no way to get sub-second accurate time in a posix shell (without involving a slow interpreter or hoping for date with %N support).Gallardo
L
22

Pure bash solution

Since bash 5.0 (released on 7 Jan 2019) you can use the built-in variable EPOCHREALTIME which contains the seconds since the epoch, including decimal places down to micro-second (μs) precision (echo $EPOCHREALTIME prints something like 1547624774.371210 in English, or 1547624774,371210 in German, French, etc.). By removing the decimal separator and the last three places we get milliseconds:

Either use

(( t = ${EPOCHREALTIME/[^0-9]/} / 1000 ))

or

t=${EPOCHREALTIME/[^0-9]/} # remove the decimal separator (s → µs)
t=${t%???}                 # remove the last three digits (µs → ms)

Either way t will be something like 1547624774371.

Lottielotto answered 11/4, 2021 at 11:53 Comment(2)
FYI the decimal separator is localized, so on my system in French, I'm getting 1695071065,749507. You can force a period with LC_ALL=C.Randa
@Randa Thank you for the hint. Very good point! I found LC_ALL to be complicated here, because we either have to use it in a subshell (which complicates setting t) or restore it manually. Both are not ideal. But I found a short general solution and updated the answer.Lottielotto
C
15

The other answers are probably sufficient in most cases but I thought I'd add my two cents as I ran into a problem on a BusyBox system.

The system in question did not support the %N format option and doesn't have no Python or Perl interpreter.

After much head scratching, we (thanks Dave!) came up with this:

adjtimex | awk '/(time.tv_sec|time.tv_usec):/ { printf("%06d", $2) }'

It extracts the seconds and microseconds from the output of adjtimex (normally used to set options for the system clock) and prints them without new lines (so they get glued together). Note that the microseconds field has to be pre-padded with zeros, but this doesn't affect the seconds field which is longer than six digits anyway. From this it should be trivial to convert microseconds to milliseconds.

If you need a trailing new line (maybe because it looks better) then try

adjtimex | awk '/(time.tv_sec|time.tv_usec):/ { printf("%06d", $2) }' && printf "\n"

Also note that this requires adjtimex and awk to be available. If not then with BusyBox you can point to them locally with:

ln -s /bin/busybox ./adjtimex
ln -s /bin/busybox ./awk

And then call the above as

./adjtimex | ./awk '/(time.tv_sec|time.tv_usec):/ { printf("%06d", $2) }'

Or of course you could put them in your PATH

EDIT:

The above worked on my BusyBox device. On Ubuntu I tried the same thing and realised that adjtimex has different versions. On Ubuntu this worked to output the time in seconds with decimal places to microseconds (including a trailing new line)

sudo apt-get install adjtimex
adjtimex -p | awk '/raw time:/ { print $6 }'

I wouldn't do this on Ubuntu though. I would use date +%s%N

Covin answered 10/8, 2016 at 11:32 Comment(2)
Wow, great alternative! Indeed your command works, but I don't have a clue why. Where do I find a documentation for the awk command?! How in hell did you find out how to build the string to extract the desired information out of the adjtimex output?Dniren
If there is a possiblity to compile Busybox yourself, enabling "CONFIG_FEATURE_DATE_NANO" would be another approach.Freon
C
11

date command didnt provide milli seconds on OS X, so used an alias from python

millis(){  python -c "import time; print(int(time.time()*1000))"; }

OR

alias millis='python -c "import time; print(int(time.time()*1000))"'

EDIT: following the comment from @CharlesDuffy. Forking any child process takes extra time.

$ time date +%s%N
1597103627N
date +%s%N  0.00s user 0.00s system 63% cpu 0.006 total

Python is still improving it's VM start time, and it is not as fast as ahead-of-time compiled code (such as date).

On my machine, it took about 30ms - 60ms (that is 5x-10x of 6ms taken by date)

$ time python -c "import time; print(int(time.time()*1000))"
1597103899460
python -c "import time; print(int(time.time()*1000))"  0.03s user 0.01s system 83% cpu 0.053 total

I figured awk is lightweight than python, so awk takes in the range of 6ms to 12ms (i.e. 1x to 2x of date):

$ time awk '@load "time"; BEGIN{print int(1000 * gettimeofday())}'
1597103729525
awk '@load "time"; BEGIN{print int(1000 * gettimeofday())}'  0.00s user 0.00s system 74% cpu 0.010 total
Center answered 16/10, 2016 at 7:29 Comment(1)
...however, once you've fork()ed off a separate process, execed your Python interpreter, let it load its libraries / otherwise initialize, write its result, and exit, that result will no longer be accurate.Denyse
K
7

To show date with time and time-zone

date +"%d-%m-%Y %T.%N %Z"

Output : 22-04-2020 18:01:35.970289239 IST

Keister answered 22/4, 2020 at 12:33 Comment(0)
P
4

I just wanted to add to Alper's answer what I had to do to get this stuff working:

On Mac, you'll need brew install coreutils, so we can use gdate. Otherwise on Linux, it's just date. And this function will help you time commands without having to create temporary files or anything:

function timeit() {
    start=`gdate +%s%N`
    bash -c $1
    end=`gdate +%s%N`
    runtime=$(((end-start)/1000000000.0))
    echo " seconds"
}

And you can use it with a string:

timeit 'tsc --noEmit'
Pothole answered 15/5, 2017 at 18:47 Comment(1)
I like this solution but I'm more interested in millis. I ported this function to my .bashrc in ubuntu: function timeit () { start=$(date +%s%N); $*; end=$(date +%s%N); runtime=$(((end-start)/1000000)); echo "$runtime ms" }Oldtimer
B
3

When you use GNU AWK since version 4.1, you can load the time library and do:

$ awk '@load "time"; BEGIN{printf "%.6f", gettimeofday()}'

This will print the current time in seconds since 1970-01-01T00:00:00 in sub second accuracy.

the_time = gettimeofday() Return the time in seconds that has elapsed since 1970-01-01 UTC as a floating-point value. If the time is unavailable on this platform, return -1 and set ERRNO. The returned time should have sub-second precision, but the actual precision may vary based on the platform. If the standard C gettimeofday() system call is available on this platform, then it simply returns the value. Otherwise, if on MS-Windows, it tries to use GetSystemTimeAsFileTime().

source: GNU awk manual

On Linux systems, the standard C function getimeofday() returns the time in microsecond accuracy.

Broker answered 18/11, 2019 at 13:24 Comment(1)
specifically GAWK, right? I tried it on regular AWK, and it failed.Arondell
R
3

I want to generate value from bash and use that value in Java code to convert back to date(java.util).

Following command works for me to generate the value in bash file:

date +%s000

Roldan answered 29/6, 2021 at 12:29 Comment(1)
Fine. I recommend we don’t use java.util.Date, though. That class is poorly designed and long outdated. Instead use Instant from java.time, the modern Java date and time API. Then you need just date %+s in bash and Instant.ofEpochSecond() in Java.Buddle
L
2

Perl can be used for this, even on exotic platforms like AIX. Example:

#!/usr/bin/perl -w

use strict;
use Time::HiRes qw(gettimeofday);

my ($t_sec, $usec) = gettimeofday ();
my $msec= int ($usec/1000);

my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
    localtime ($t_sec);

printf "%04d-%02d-%02d %02d:%02d:%02d %03d\n",
    1900+$year, 1+$mon, $mday, $hour, $min, $sec, $msec;
Lynnette answered 28/11, 2018 at 11:20 Comment(0)
K
1

A Python script like this:

import time
cur_time = int(time.time()*1000)
Kyliekylila answered 23/6, 2015 at 22:9 Comment(4)
this will not return the number of milliseconds, this will return the number of seconds expressed in milliseconds. Everything will be $SECONDS000Homeric
@Homeric maoyang's Python code is providing milliseconds.Racism
@jlliagre: But is the actual time resolution better than 16-17 ms (1/60 second) or not?Atheistic
Yes, Python's time.time() returns a float to 6 decimal places, at least on macOS.Lib
I
0

To print decimal seconds:

start=$(($(date +%s%N)/1000000)) \
    && sleep 2 \
    && end=$(($(date +%s%N)/1000000)) \
    && runtime=$((end - start))

divisor=1000 \
    && foo=$(printf "%s.%s" $(( runtime / divisor )) $(( runtime % divisor ))) \
    && printf "runtime %s\n" $foo # in bash integer cannot cast to float

Output: runtime 2.3

Imprescriptible answered 21/12, 2021 at 12:47 Comment(0)
S
0

To get date in mili-seconds you can use:

date +"%T:%N"
Social answered 22/9, 2023 at 6:38 Comment(1)
date +"%T:%N" outputs 11:20:57:N on macOS 14.2.1. (I couldn't figure out the version of this date binary, unfortunately.)Blume
B
-1

What about using the simple BASH intrinsic variable EPOCHREALTIME?

Bever answered 3/7, 2023 at 12:36 Comment(1)
This was already recommended in another answer.Lukewarm

© 2022 - 2024 — McMap. All rights reserved.