337

How do I get the current Unix time in milliseconds (i.e number of milliseconds since Unix epoch January 1 1970)?

Peter Mortensen
  • 2,319
  • 5
  • 23
  • 24
Richard
  • 3,652
  • 2
  • 17
  • 13

19 Answers19

402

This:

date +%s 

will return the number of seconds since the epoch.

This:

date +%s%N

returns the seconds and current nanoseconds.

So:

date +%s%N | cut -b1-13

will give you the number of milliseconds since the epoch - current seconds plus the left three of the nanoseconds.


and from MikeyB - echo $(($(date +%s%N)/1000000)) (dividing by 1000 only brings to microseconds)

warren
  • 17,829
  • 23
  • 82
  • 134
  • 52
    I wonder how many ms the cut adds :-) – Kyle Brandt Jun 14 '10 at 16:23
  • you're looking at screen refresh time - that's already going to add *something* :) – warren Jun 14 '10 at 16:32
  • 3
    I think seconds * 1000 will be fine :) – Richard Jun 14 '10 at 16:34
  • 13
    Or if you want to do it all in the shell, avoiding the expensive overhead of an additional process (actually, we're avoiding the problem when the number of digits in %+s+N changes): `echo $(($(date +%s%N)/1000))` – MikeyB Jun 14 '10 at 16:38
  • 1
    @MikeyB - when will the number of digits change? we're only in the single digit billions for seconds now.. which means at least another 7x40 years before it'd be something to worry about, no? (Presuming, of course, we don't hit the Unix time wall first) – warren Jun 14 '10 at 17:48
  • 5
    It's the principle of the matter... avoid magic numbers and code what you actually *mean*. – MikeyB Jun 14 '10 at 18:02
  • then technically yours has magic numbers, too :) – warren Jun 14 '10 at 19:54
  • 29
    I think it's worth noting that the man asked for Unix, not Linux, and the current top answer (date +%s%N) doesn't work on my AIX system. – Pete Oct 25 '11 at 16:52
  • 15
    @Pete +1 Same for OS X, and FreeBSD – ocodo May 19 '12 at 00:28
  • I think it is important to note that the division does **NOT** give you the milliseconds! You need to divide by 1,000,000! *(Since 1s is 1,000,000,000ns and 1s is 1000ms. Therefore 1ms is 1,000,000ns)* – BrainStone May 12 '15 at 21:20
  • @BrainStone - the division option *is* dividing by 1,000,000 – warren May 13 '15 at 12:53
  • 2
    @warren Youn are right. I was reffering to the one in the comments. I did not see the one in the answer... – BrainStone May 13 '15 at 13:00
  • 11
    `%N` does not work on OSX Yosemite – Matt Clark Jun 03 '15 at 20:32
  • 1
    @MattClark - there doesn't seem to be a format specifier for the BSD `date` command for nanoseconds – warren Jun 03 '15 at 20:56
  • 3
    on OS X your best bet might be brew coreutils, then you can `gdate +%s%N` – rymo Sep 05 '15 at 15:09
  • The last option does not work on OS X: echo $(($(date +%s%N)/1000000)) -bash: 1448370039N: value too great for base (error token is "1448370039N") – oligofren Nov 24 '15 at 13:01
  • https://en.wikipedia.org/wiki/Observer_effect_(physics) Even if you do all kinds of tricks moving away all kinds of additional processes, the time used for moving the calculation to other cores/threads still count! (OCD) – SOFe Jul 06 '16 at 14:23
  • 2
    Instead of using `cut -b1-13`, one could use the bash substring: `dt=$(date +%s%N); ${dt:1:13}`. – haridsv Mar 21 '17 at 08:46
  • 1
    If you are doing math to adjust the order of magnitude after specifying a format, you are doing it wrong. [Joe did it the right way](https://serverfault.com/a/588705/4131). – Bruno Bronosky Apr 30 '18 at 19:58
  • Would this not work on macOs? echo $(($(date +%s)*1000)) – Brill Pappin Aug 21 '20 at 20:48
  • @BrillPappin - no. That multiplies the current *seconds* by 1000. – warren Aug 24 '20 at 13:16
  • @warren yes exactly, if he's asking for milliseconds, then 1 second == 1000 milliseconds, as far as I remember. – Brill Pappin Aug 24 '20 at 17:52
  • 1
    @BrillPappin - but merely *multiplying* seconds by 1000 doesn't give "current Unix time in milliseconds": it gives you "the current second as if it were milliseconds". In other words, You won't get 1598360260075 or 1598360260901. You would get 1598360260000. Your method will be somewhere between "exactly correct" and "off by as much as 999 milliseconds". If *millisecond precision* is necessary (a pretty common use case), then being off by as much as 999ms is totally unacceptable :) – warren Aug 25 '20 at 12:59
  • @warren ahh, of course, makes sense :) you still need to know what those fractions of a second are. – Brill Pappin Aug 29 '20 at 17:07
  • Shouldn't this: `date +%s%N` actually be this, to insert the decimal between the seconds and nanoseconds?: `date +%s.%N` – Gabriel Staples Dec 27 '20 at 22:37
  • @GabrielStaples - if you wanted the decimal, probably. But that's not what OP asked for (when I answered) – warren Dec 28 '20 at 12:59
176

You may simply use %3N to truncate the nanoseconds to the 3 most significant digits (which then are milliseconds):

$ date +%s%3N
1397392146866

This works e.g. on my Kubuntu 12.04 (Precise Pangolin).

But be aware that %N may not be implemented depending on your target system. E.g. tested on an embedded system (buildroot rootfs, compiled using a non-HF ARM cross toolchain) there was no %N:

$ date +%s%3N
1397392146%3N

(And also my (non rooted) Android tablet doesn't have %N.)

Peter Mortensen
  • 2,319
  • 5
  • 23
  • 24
Joe
  • 1,863
  • 1
  • 10
  • 7
  • 1
    @warren: I saw that you edited and changed the `1397392146%3N` to `1397392146%N`, but the output of `1397392146%3N` is that what I'd really seen on the busybox console of my android tablet. Could you explain your edit? – Joe Jun 25 '15 at 08:00
  • warren's comment from the history is "changed from 3 to 6, as 3 only takes you to microseconds". His edit seems entirely spurious; you should roll it back. – bukzor Dec 25 '15 at 00:27
  • 2
    This is a feature of GNU coreutils specifically. Ultimately, this is implemented in gnulib here: https://github.com/gagern/gnulib/blob/71090a2a314d9c378afd6f842abb49f60b42d4ef/lib/strftime.c#L1085. – telotortium Nov 06 '17 at 20:23
  • probably a dot in there makes sense. `date +%s.%3N` prints `1510718281.134`. – darksky Nov 15 '17 at 04:01
  • 2
    This should be the accepted answer. – Noah Sussman Apr 30 '19 at 15:29
  • What is *"HF"*? – Peter Mortensen Nov 18 '19 at 13:40
  • @PeterMortensen Hard Float. ARM CPUs with hardware support for floating point numbers, as opposed to Soft Float where that has to be done slowly in software. – Different55 Jan 30 '20 at 17:28
88

date +%N doesn't work on OS X, but you could use one of

  • Ruby: ruby -e 'puts Time.now.to_f'
  • Python: python -c 'import time; print(int(time.time() * 1000))'
  • Node.js: node -e 'console.log(Date.now())'
  • PHP: php -r 'echo microtime(TRUE);'
  • Elixir: DateTime.utc_now() |> DateTime.to_unix(:millisecond)
  • The Internet: wget -qO- http://www.timeapi.org/utc/now?\\s.\\N
  • or for milliseconds rounded to nearest second date +%s000
Lri
  • 989
  • 6
  • 3
  • 1
    for completeness... `node -e 'console.log(Date.now())'` – slf Oct 10 '13 at 18:06
  • 1
    Using PHP: `php -r 'echo microtime(TRUE);'` – TachyonVortex Nov 22 '13 at 16:41
  • 9
    Sure, you just have to wait for those interpreters to warm up. This works, too: `wget -qO- http://www.timeapi.org/utc/now?\\s.\\N` – Camilo Martin Jun 23 '14 at 13:26
  • 10
    Or, if you *don't actually need the milliseconds* but just the correct format: `date +%s000` – Lenar Hoyt Apr 22 '15 at 16:15
  • @CamiloMartin: I love your (tongue-in-cheek?) wget exemple to get milliseconds precision out of a (remote) request to a website ^^. Locally, a few of the examples above are indeed probably closer to the tenth-of-a-second or maybe hundredth-of-a-second precision – Olivier Dulac Jan 22 '16 at 16:56
  • @OlivierDulac yes, I wouldn't recommend that seriously! That said, it's [far too common](https://www.reddit.com/r/Bitcoin/comments/29zx7z/) to see code that would break if someone, somewhere, decided to have some fun. Also, tenth-of-a-second?! In reality you can take the fractional part and redirect it to `/dev/random` to improve the system's entropy pool. – Camilo Martin Jan 22 '16 at 20:10
  • Perl: `echo "1487787384024" | perl -MTime::Piece -pe 's/(\d{13})/Time::Piece->localtime($1 \/1000)->strftime("%Y-%m-%d %a")/e'` . The nice thing about this is that you can feed a whole line of text containing a 13-digit timestamp and it will perform a substitution and leave the rest of the text as-is – Sridhar Sarnobat Feb 28 '17 at 01:36
  • 1
    https://apple.stackexchange.com/questions/135742/time-in-milliseconds-since-epoch-in-the-terminal has instructions for doing this in OSX via Brew's `coreutils` – sameers Nov 17 '17 at 19:53
  • As @sameers pointed out: you can install `coreutils` on macOS with `brew install coreutils` and then `gdate +%N` will work. – psmith May 18 '20 at 03:16
21

My solution is not the best, but it worked for me:

date +%s000

I just needed to convert a date like 2012-05-05 to milliseconds.

Peter Mortensen
  • 2,319
  • 5
  • 23
  • 24
Pablo
  • 227
  • 2
  • 2
11

Just throwing this out there, but I think the correct formula with the division would be:

echo $(($(date +%s%N)/1000000))
splattne
  • 28,348
  • 19
  • 97
  • 147
10

This solution works on macOS.

If you consider using a Bash script and have Python available, you could use this code:

#!/bin/bash

python -c 'from time import time; print int(round(time() * 1000))'
Peter Mortensen
  • 2,319
  • 5
  • 23
  • 24
Frank Thonig
  • 101
  • 1
  • 5
8

For the people that suggest running external programs to get the milliseconds... at that rate, you might as well do this:

wget -qO- http://www.timeapi.org/utc/now?\\s.\\N

Point being: before picking any answer from here, please keep in mind that not all programs will run under one whole second. Measure!

Camilo Martin
  • 375
  • 1
  • 4
  • 11
  • You're not asking the local system for the time. Which I guess is implied in the question. You also depend on a network connection. – orkoden Jan 29 '15 at 11:27
  • 2
    @orkoden The question explicitly asks for "number of milliseconds since Unix epoch January 1 1970". Also, I'm more of pointing out how you shouldn't ever fire up whole of Ruby or Python (or wget) just to get the time - either this is done through a fast channel or milliseconds don't matter. – Camilo Martin Jan 29 '15 at 11:57
  • 3
    Yes, I understood that you were giving a worse solution to highlight the bad solutions' flaws. I tried several solutions and measured the time. http://lpaste.net/119499 The results are kind of interesting. Even on a very fast i7 machine `date` takes 3 ms to run. – orkoden Jan 29 '15 at 12:38
  • @orkoden Nice testing! What OS? This might have to do with process spawning overhead. – Camilo Martin Jan 30 '15 at 13:18
  • I used OS X 10.10.2. – orkoden Jan 30 '15 at 16:44
  • @orkoden Complementing that with a couple other platforms: http://pastebin.com/raw.php?i=q6Y6Beaj – Camilo Martin Jan 31 '15 at 08:19
  • You're running `date` twice and then subtracting, while also using `awk`. This seems to be inexact, because `awk` also takes up some of that time. Why aren't you using `time`? – orkoden Jan 31 '15 at 11:08
  • @orkoden Both are run one next to the other in `bash`'s "command substitution" phase, and when `awk` sees them, they're just literal values. If you assume running `date` will always take about the same time (which it seems to be), the difference between when one value was ready vs. when the next value was ready will give you the run time of `date` itself. `time` gives me way more fluctuation than doing this so I guess `time` is not very precise. – Camilo Martin Jan 31 '15 at 11:21
  • It's already dead. – Nakilon May 15 '17 at 15:49
  • 2
    @Nakilon and this is why one shouldn't rely on curl-able conveniences like those for anything production. – Camilo Martin May 17 '17 at 22:24
  • Perfect, *Ctrl-c*, open production code, *Ctrl-v* – Z4-tier Sep 09 '20 at 23:30
5

If you are looking for a way to display the length of time your script ran, the following will provide a (not completely accurate) result:

As near the beginning of your script as you can, enter the following

basetime=$(date +%s%N)

This'll give you a starting value of something like 1361802943996000000.

At the end of your script, use the following

echo "runtime: $(echo "scale=3;($(date +%s%N) - ${basetime})/(1*10^09)" | bc) seconds"

which will display something like

runtime: 12.383 seconds

Notes:

(1*10^09) can be replaced with 1000000000 if you wish

"scale=3" is a rather rare setting that coerces bc to do what you want. There are lots more!

I only tested this on Windows 7/MinGW... I don't have a proper *nix box at hand.

Peter Mortensen
  • 2,319
  • 5
  • 23
  • 24
user161733
  • 51
  • 1
  • 1
2

Another solution for MacOS: GNU Coreutils

I have noticed that the MacOS' version of the date command is not interpreting the %N format sequence as nanoseconds but simply prints N to the output when I started using my .bashrc script from Linux, that's using it to measure how long executed commands run, on a MacOS machine.

After a little bit of research, I have learned that only the GNU date from the GNU Coreutils package does support milliseconds. Fortunately, it's pretty easy to install it on MacOS using Homebrew:

brew install coreutils

Since that package contains executables that are already present on MacOS, Coreutils' executables will be installed with a g prefix, so date will be available as gdate.

See for example this page for further details.

2

Here is how to get time in milliseconds without performing division. Maybe it's faster...

# test=`date +%s%N`
# testnum=${#test}
# echo ${test:0:$testnum-6}
1297327781715

Update: Another alternative in pure Bash that works only with Bash 4.2+ is the same as above, but use printf to get the date. It will definitely be faster, because no processes are forked off the main one.

printf -v test '%(%s%N)T' -1
testnum=${#test}
echo ${test:0:$testnum-6}

Another catch here though is that your strftime implementation should support %s and %N which is not the case on my test machine. See man strftime for supported options. Also see man bash to see printf syntax. -1 and -2 are special values for time.

Peter Mortensen
  • 2,319
  • 5
  • 23
  • 24
akostadinov
  • 1,118
  • 1
  • 9
  • 18
2

The most accurate timestamp we can get for Mac OS X is probably this:

python3 -c 'import datetime; print(datetime.datetime.now().strftime("%s.%f"))'

1490665305.021699

But we need to keep in mind that it takes around 30 milliseconds to run. We can cut it to the scale of 2 digits fraction, and at the very beginning compute the average overhead of reading the time, and then remove it off the measurement. Here is an example:

function getTimestamp {
  echo `python -c 'import datetime; print datetime.datetime.now().strftime("%s.%f")' | cut -b1-13` 
}
function getDiff {
  echo "$2-$1-$MeasuringCost" | bc
}
prev_a=`getTimestamp`
acc=0
ITERATIONS=30
for i in `seq 1 $ITERATIONS`;do 
  #echo -n $i 
  a=`getTimestamp`
  #echo -n "   $a"
  b=`echo "$a-$prev_a" | bc`
  prev_a=$a
  #echo "  diff=$b"
  acc=`echo "$acc+$b" | bc`
done
MeasuringCost=`echo "scale=2; $acc/$ITERATIONS" | bc`
echo "average: $MeasuringCost sec"
t1=`getTimestamp`
sleep 2
t2=`getTimestamp`
echo "measured seconds: `getDiff $t1 $t2`"

You can uncomment the echo commands to see better how it works.

The results for this script are usually one of these 3 results:

measured seconds: 1.99
measured seconds: 2.00
measured seconds: 2.01
Paul Merrill
  • 103
  • 5
ishahak
  • 501
  • 4
  • 8
2

Not adding anything revolutionary here over the accepted answer, but just to make it reusable easily for those of you whom are newer to Bash. Note that this example works in OS X and on older Bash which was a requirement for me personally.

nowInMs() {
  echo "$(($(date +'%s * 1000 + %-N / 1000000')))"
}

Now you can run

TIMESTAMP="$(nowInMs)";
Peter Mortensen
  • 2,319
  • 5
  • 23
  • 24
1

Perl solution

perl -mTime::HiRes -e 'printf "%.0f\n", (Time::HiRes::time() * 1000 )'

Time::HiRes::time() returns a float of the form unixtimeinsec.microseconds

Multiply by 1000 to shift left 3 digits, and output with no decimal digits.
Why not just convert to integer with %d?
Because it'll overflow a signed (or unsigned) integer on a 32 bit OS, such as our ancient AIX servers.

As others have pointed out, it's a question of portability. The accepted answer works on linux or anything that can run gnu date, but not on several other UNIX flavors. Personally I find our older systems are much more likely to have perl than python, Node.js, Ruby or PHP.

Yes, date +%s%3N (if available) is about 5x faster than perl).

Ian
  • 11
  • 2
1

Using date and expr can get you there i.e.

X=$(expr \`date +%H\` \\* 3600 + \`date +%M\` \\* 60 + \`date +%S\`)
echo $X

Just expand on it to do whatever you want

I realise this does not give milliseconds since epoch, but it might still be useful as an answer for some of the cases, it all depends on what you need it for really, multiply by 1000 if you need a millisecond number :D

Simplest way would be to make a small executable (from C f.ex.) and make it available to the script.

kasperd
  • 29,894
  • 16
  • 72
  • 122
  • There's a potential problem running `date` multiple times. In some cases, the date or time may change between runs as your command is written. It's better to run `date` once and parse the parts out and do your calculation. One of several ways to do that would be `t=$(date +%H%M%S); (( x = ${t:0:2} * 3600 + ${t:2:2} * 60 + ${t:4:2} )); echo "$x"`. This uses Bash syntax since the question is tagged [tag:bash]. As you allude, your answer (and my variation) only gives seconds for the current day so far and not since the Epoch and not in millis. – Dennis Williamson Nov 04 '15 at 00:17
1

(repeat from previous answers) date +%N doesn't work on OS X, but you could also use:

Perl (requires Time::Format module). Perhaps it is not the best CPAN module to use, but it gets the job done. Time::Format is generally made available with distributions.

perl -w -e'use Time::Format; printf STDOUT ("%s.%s\n", time, $time{"mmm"})'
Peter Mortensen
  • 2,319
  • 5
  • 23
  • 24
TVNshack
  • 11
  • 2
  • The OP specifically asked for ways to do it using bash. How is this bash, save as a method to launch something else? – MadHatter Mar 15 '16 at 10:48
  • I use this in my bash shell scripts ... under OSX. So, `date` can't be used and there is no bash-only commands that answer the need. – TVNshack Mar 15 '16 at 13:37
  • Fair enough. If you were to clarify why OSX's `date` can't be used **as part of your answer**, I'd remove my downvote. – MadHatter Mar 15 '16 at 13:43
  • This was explained a few answers above. I couldn't add as comment that command which was missing with the proposed list. So I've added it here. – TVNshack Mar 15 '16 at 14:56
  • Fair enough, I accept this is a useful addition to the canon. +1 from me! – MadHatter Mar 15 '16 at 15:32
1

Putting the previous responses all together, when in OS X,

ProductName:    Mac OS X
ProductVersion:    10.11.6
BuildVersion:    15G31+

you can do like

microtime() {
    python -c 'import time; print time.time()'
}
compute() {
    local START="$(microtime)"
    #$1 is command $2 are args
    local END="$(microtime)"
    DIFF="$(bc <<< "$END - $START")"
    echo "$1\t$2\t$DIFF"
}
loretoparisi
  • 133
  • 1
  • 7
1

For Alpine Linux (many Docker images) and possibly other minimal Linux environments, you can abuse adjtimex:

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

adjtimex is used to read (and set) kernel time variables. With awk you can get the microseconds, and with head you can use the first 3 digits only.

I have no idea how reliable this command is.

Note: Shamelessly stolen from this answer

Peter Mortensen
  • 2,319
  • 5
  • 23
  • 24
Qw3ry
  • 111
  • 2
0

https://github.com/ysoftwareab/nanoseconds

I've just created this cross-platform project via golang to output nanoseconds since Unix epoch. As simple as that. Download your-platform-of-choice executable from a Github release.

Getting granular timestamps is important for benchmarks (e.g. OpenTelemetry). Depending on GNU/coreutils/insert-programming-language is in many cases a no go.

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jul 02 '22 at 17:19
0

If you want a simple shell elapsed computation, this is easy and portable, using Frank Thonig's answer:

now() {
    python -c 'import datetime; print datetime.datetime.now().strftime("%s.%f")'
}
seismo:~$ x=`now`
seismo:~$ y=`now`
seismo:~$ bc <<< "$y - $x"
5.212514