Luciano
Luciano

Reputation: 3009

Getting the localtime in milliseconds

I need the fastest way to get the localtime (thus considering the current timezone) at least in milliseconds precision, if is possible to get in tenths of milliseconds it would be better.

I would like to avoid the use of gettimeofday() as it is now an obsolete function.

So, there seems that I'll need to use the clock_gettime(CLOCK_REALTIME, ...) and adjust the hour to the current timezone, but how ? And where is the best point to do that ? Before to store the timestamp got with clock_gettime, or before to convert it in a gregorian calendar in the current timezone?

EDIT: My original sample joining get_clock and localtime - There are better ways to reach that?

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

int main() {
    struct timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);

    struct tm* ptm;
    ptm = localtime(&(ts.tv_sec));

    // Tenths of milliseconds (4 decimal digits)
    int tenths_ms = ts.tv_nsec / (100000L);

    printf("%04d-%02d-%02d %02d:%02d:%02d.%04d\n", 
        1900 + ptm->tm_year, ptm->tm_mon + 1, ptm->tm_mday, 
        ptm->tm_hour, ptm->tm_min, ptm->tm_sec, tenths_ms);
}

Upvotes: 2

Views: 3362

Answers (2)

siho
siho

Reputation: 131

I don't think there's a better way than with clock_gettime() and localtime(). However you need to round the returned nanoseconds correctly and consider the case when the time is rounded up to the next second. To format the time you can use strftime() instead of formatting the tm struct manually:

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

int main(void) {
    struct timespec ts;
    long msec;
    int err = clock_gettime(CLOCK_REALTIME, &ts);
    if (err) {
        perror("clock_gettime");
        return 1;
    }

    // round nanoseconds to milliseconds
    if (ts.tv_nsec >= 999500000) {
        ts.tv_sec++;
        msec = 0;
    } else {
        msec = (ts.tv_nsec + 500000) / 1000000;
    }

    struct tm* ptm = localtime(&ts.tv_sec);
    if (ptm == NULL) {
        perror("localtime");
        return 1;
    }

    char time_str[sizeof("1900-01-01 23:59:59")];
    time_str[strftime(time_str, sizeof(time_str),
            "%Y-%m-%d %H:%M:%S", ptm)] = '\0';

    printf("%s.%03li\n", time_str, msec);
}

Upvotes: 3

iqstatic
iqstatic

Reputation: 2382

Yes, this can be achieved using the 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().

Long story short, 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_in_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

    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.

One more point, remember to include -lm flag when trying to compile the code.

To get the timezone, just do the following:

#define _GNU_SOURCE /* for tm_gmtoff and tm_zone */

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

int main(void)
{
  time_t t = time(NULL);
  struct tm lt = {0};

  localtime_r(&t, &lt);

  printf("Offset to GMT is %lds.\n", lt.tm_gmtoff);
  printf("The time zone is '%s'.\n", lt.tm_zone);

  return 0;
}

Note: The seconds since epoch returned by time() are measured as if in GMT (Greenwich Mean Time).

Upvotes: 2

Related Questions