22

I was trying out this function in a C program, and it keeps printing the wrong time. This is my code at the moment:

#include <stdio.h> #include <unistd.h> #include <time.h> #include <sys/resource.h> int main( int argc, char **argv ){ struct timespec start, finish; clock_gettime( CLOCK_REALTIME, &start ); sleep( 1 ); clock_gettime( CLOCK_REALTIME, &finish ); printf( "%f\n", ((double) (finish.tv_nsec - start.tv_nsec))/((double) 100000) ); return 0; } 

I'm not sure if this is an anomaly caused by rounding errors when converting to a double or if I'm using the clock_gettime() function incorrectly, but I expected it to output 1 second and instead it outputs 1.27 seconds.

5
  • 3
    1 nanosecond is 1000000000 seconds. Also if you start at second 33.433 and stop at second 34.42991, the difference finish.tv_nsec - start.tv_nsec is negative Commented Dec 10, 2018 at 14:52
  • 1
    That's not a reliable time delta calculation. You need to compute using the whole seconds as well as the nanoseconds in general, though you'll often get away with it. The number output is tenths of milliseconds — that's plausible for the overhead of system calls and scheduling. But: you ignore the difference of one whole second recorded in the tv_sec elements of the time specs. Commented Dec 10, 2018 at 14:53
  • So is tv_nsec the number of nanoseconds modulo the second? Commented Dec 10, 2018 at 14:54
  • That would explain why the number was too small when I divided by 1 billion. Commented Dec 10, 2018 at 14:54
  • 1
    The tv_nsec is the number of nanoseconds within the current second. It ranges (in theory) between 0 and 999,999,999. This allows an integer number of whole seconds to be stored in tv_sec and a fraction of a second to be stored in tv_nsec. Actual resolution is another issue: see clock_getres() for that. On a Mac, for instance, the resolution is microseconds, even though those are expressed in nanoseconds. Commented Dec 10, 2018 at 14:55

1 Answer 1

27

You need to take into account the tv_sec member of the structure when calculating the time difference between two values returned by clock_gettime().

The tv_nsec is the number of nanoseconds within the current second. It ranges (in theory) between 0 and 999,999,999. This allows an integer number of whole seconds to be stored in tv_sec and a fraction of a second to be stored in tv_nsec. Actual resolution is another issue: see clock_getres() for that. On a Mac, for instance, the resolution is microseconds, even though those are expressed in nanoseconds.

Consider using code like this:

#include <stdio.h> #include <time.h> #include <unistd.h> enum { NS_PER_SECOND = 1000000000 }; void sub_timespec(struct timespec t1, struct timespec t2, struct timespec *td) { td->tv_nsec = t2.tv_nsec - t1.tv_nsec; td->tv_sec = t2.tv_sec - t1.tv_sec; if (td->tv_sec > 0 && td->tv_nsec < 0) { td->tv_nsec += NS_PER_SECOND; td->tv_sec--; } else if (td->tv_sec < 0 && td->tv_nsec > 0) { td->tv_nsec -= NS_PER_SECOND; td->tv_sec++; } } int main(void) { struct timespec start, finish, delta; clock_gettime(CLOCK_REALTIME, &start); sleep(1); clock_gettime(CLOCK_REALTIME, &finish); sub_timespec(start, finish, &delta); printf("%d.%.9ld\n", (int)delta.tv_sec, delta.tv_nsec); return 0; } 

When run (as cgt61), I get results like:

$ cgt61 1.004930000 $ cgt61 1.004625000 $ cgt61 1.003023000 $ cgt61 1.003343000 $ 

This was tested on a Mac; you can see that the final three digits are always zeros. In a Linux VM (Ubuntu 18.04 on a Mac), I had to add #define _POSIX_C_SOURCE 200809L to the code (because I compile with -std=c11; if I used -std=gnu11, I would have been OK), and the output was:

$ ./cgt61 1.000589528 $ 
Sign up to request clarification or add additional context in comments.

3 Comments

In this if condition - (td->tv_sec < 0 && td->tv_nsec > 0), is it possible that this td->tv_sec < 0 will ever result in true?
You won't get tv_sec < 0 from a call to clock_gettime() (unless the system clock is set horribly wrong), but if the user has created a time before 1970-01-01 00:00:00Z, then the tv_sec value will be negative.
Fair enough. if the user has created a time before 1970-01-01 00:00:00Z, then.... - its only possible when someone explicitly do it on the a system otherwise there is no way that this condition td->tv_sec < 0 will result in true.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.