110

How do I get the current time on Linux in milliseconds?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
LLL
  • 1,273
  • 3
  • 10
  • 8

8 Answers8

131

This can be achieved using the POSIX clock_gettime function.

In the current version of POSIX, gettimeofday is marked obsolete. This means it may be removed from a future version of the specification. Application writers are encouraged to use the clock_gettime function instead of gettimeofday.

Here is an example of how to use clock_gettime:

#define _POSIX_C_SOURCE 200809L

#include <inttypes.h>
#include <math.h>
#include <stdio.h>
#include <time.h>

void print_current_time_with_ms (void)
{
    long            ms; // Milliseconds
    time_t          s;  // Seconds
    struct timespec spec;

    clock_gettime(CLOCK_REALTIME, &spec);

    s  = spec.tv_sec;
    ms = round(spec.tv_nsec / 1.0e6); // Convert nanoseconds to milliseconds
    if (ms > 999) {
        s++;
        ms = 0;
    }

    printf("Current time: %"PRIdMAX".%03ld seconds since the Epoch\n",
           (intmax_t)s, ms);
}

If your goal is to measure elapsed time, and your system supports the "monotonic clock" option, then you should consider using CLOCK_MONOTONIC instead of CLOCK_REALTIME.

Raedwald
  • 46,613
  • 43
  • 151
  • 237
Dan Moulding
  • 211,373
  • 23
  • 97
  • 98
  • 8
    +1 for being POSIXly correct — but your answer has the wrong units. The OP doesn't want the time _with_ milliseconds, but the time _in_ milliseconds. – pilcrow Jun 28 '13 at 19:50
  • 8
    Good solution but don't forget the _-lm_ in your `gcc` command. – David Guyon Jun 02 '14 at 08:58
  • 3
    according to the manpage for round, you want to use lround when assigning the result to an integer (or long) – hildred Mar 21 '16 at 21:42
  • @hildred That's a good point, but in this case using `round` is safe and will always give an equivalent value to `lround`. That's because `tv_nsec` is itself a long, so the result of `round(spec.tv_nsec / 1.0e6)` can never be anything that won't correctly convert to a `long`. It will never try to round NaN or infinity and the result will always, by definition, be within range of `long`. – Dan Moulding Mar 22 '16 at 16:20
  • 4
    You need to use floor() instead of round() so that it never rounds up to 1000 ms. Otherwise you would need to increment `s` when this happens. Probably a rare event but the extra digit can cause trouble. – Mike Dec 27 '17 at 00:55
  • 1
    @Mike Nice catch. At one in two thousand, it's not even that rare, so should definitely be fixed. Rather than use floor, I think I'd prefer to maintain a little more accuracy and continue to round, but increment the second counter if it rounds up to 1000. – Dan Moulding Dec 27 '17 at 20:11
  • An improvement to this would be to add to `s` to reflect how many seconds have passed. Something like: `remainder = ms % 1000; s += ((ms - remainder) / 1000) - 1; ms = remainder`. Otherwise you lose any extra seconds and milliseconds. – SamTebbs33 Jan 14 '19 at 16:15
  • 3
    @SamTebbs33 there should never be any extra milliseconds. `spec.tv_nsec` will always be less than 1 billion (and hence ms will never be more than 1000 after rounding). – Dan Moulding Jan 19 '19 at 04:53
67

You have to do something like this:

struct timeval  tv;
gettimeofday(&tv, NULL);

double time_in_mill = 
         (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000 ; // convert tv_sec & tv_usec to millisecond
alkar
  • 5,459
  • 7
  • 27
  • 43
yadab
  • 2,063
  • 1
  • 16
  • 24
39

Following is the util function to get current timestamp in milliseconds:

#include <sys/time.h>

long long current_timestamp() {
    struct timeval te; 
    gettimeofday(&te, NULL); // get current time
    long long milliseconds = te.tv_sec*1000LL + te.tv_usec/1000; // calculate milliseconds
    // printf("milliseconds: %lld\n", milliseconds);
    return milliseconds;
}

About timezone:

gettimeofday() support to specify timezone, I use NULL, which ignore the timezone, but you can specify a timezone, if need.


@Update - timezone

Since the long representation of time is not relevant to or effected by timezone itself, so setting tz param of gettimeofday() is not necessary, since it won't make any difference.

And, according to man page of gettimeofday(), the use of the timezone structure is obsolete, thus the tz argument should normally be specified as NULL, for details please check the man page.

Andrii Omelchenko
  • 13,183
  • 12
  • 43
  • 79
Eric
  • 22,183
  • 20
  • 145
  • 196
  • 1
    > gettimeofday() support to specify timezone, I use NULL, which ignore the timezone, but you can specify a timezone, if need. You are wrong. Time zone should be introduced exclusively via call to localtime(). – vitaly.v.ch Nov 04 '17 at 02:55
  • @vitaly.v.ch I did a test, passing the `tz` param of `gettimeofday()` as `&(struct timezone tz = {480, 0})` won't get any warning, and it don't have any effect to the result, that makes sense, since the `long` representation of time is not relevant to or effected by timezone itself, right? – Eric Nov 05 '17 at 06:33
  • There was no reason to do any test. Linux kernel does not have proper information about time-zones, and at the same time does not have a way to provide it. It a reason why tz argument is processed in very specific way. long representation does not matter. – vitaly.v.ch Nov 05 '17 at 10:54
  • @vitaly.v.ch At a specific time point, long representation don't varies due to timezone, that's why it matters, and due to that normally only `NULL` is the reasonable value to pass. And, I believe testing is always a good approach to prove things. – Eric Nov 05 '17 at 12:28
12

Use gettimeofday() to get the time in seconds and microseconds. Combining and rounding to milliseconds is left as an exercise.

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
8

C11 timespec_get

It returns up to nanoseconds, rounded to the resolution of the implementation.

It is already implemented in Ubuntu 15.10. API looks the same as the POSIX clock_gettime.

#include <time.h>
struct timespec ts;
timespec_get(&ts, TIME_UTC);
struct timespec {
    time_t   tv_sec;        /* seconds */
    long     tv_nsec;       /* nanoseconds */
};

More details here: https://stackoverflow.com/a/36095407/895245

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
3

Derived from Dan Moulding's POSIX answer, this should work :

#include <time.h>
#include <math.h>

long millis(){
    struct timespec _t;
    clock_gettime(CLOCK_REALTIME, &_t);
    return _t.tv_sec*1000 + lround(_t.tv_nsec/1e6);
}

Also as pointed out by David Guyon: compile with -lm

Jirka Justra
  • 187
  • 1
  • 7
3

This version need not math library and checked the return value of clock_gettime().

#include <time.h>
#include <stdlib.h>
#include <stdint.h>

/**
 * @return milliseconds
 */
uint64_t get_now_time() {
  struct timespec spec;
  if (clock_gettime(1, &spec) == -1) { /* 1 is CLOCK_MONOTONIC */
    abort();
  }

  return spec.tv_sec * 1000 + spec.tv_nsec / 1e6;
}
FH0
  • 61
  • 1
  • 5
  • 2
    Please state what your answer brings over the 6 other answers (in particular, given that 2 other answers already rely on `clock_gettime`), add which headers it requires, and in what way it addresses the OP's question. Concerning `CLOCK_MONOTONIC`, I would also recommend using standard macros directly in your answers (and in your code, in general) instead of literals. – PiCTo Nov 25 '20 at 11:40
  • 2
    While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value. – Donald Duck Nov 25 '20 at 11:55
0

Jirka Justra's answer returns a long, which is usually 32 bits. The number of milliseconds since unix time 0 in 1970 requires more bits, so the data type should be long long or unsigned long long, which is usually 64 bits. Also, as Kevin Thibedeau commented, rounding can be done without converting to floating point or using math.h.

#include <time.h>
long long millis () {
  struct timespec t ;
  clock_gettime ( CLOCK_REALTIME , & t ) ;
  return t.tv_sec * 1000 + ( t.tv_nsec + 500000 ) / 1000000 ;
}

If you are trying to measure time less than 50 days, 32 bits is enough. Data type int is 32 bits or 64 bits on most computers, so the data type can be unsigned int.