11

Im working with the clock_gettime() command and trying to append a given amount of milliseconds to the timespec that I get from it. Can I just do this?

//milli is an int that can be any number (within reason)
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_nesc += (milli*1000000);

or do I need to split it up and find out if there are any whole seconds first, add those to the tv_sec field, and then add the remaining to the tv_nsec?

Essentially, can the tv_nsec field store more than 1 seconds worth of nanoseconds?

Nealon
  • 2,213
  • 6
  • 26
  • 40

2 Answers2

14

It depends entirely on what you're going to do with it.

The tv_nsec members of a struct timespec is of type long. You can set it to any value you like in the range LONG_MIN to LONG_MAX. If you perform a calculation that exceeds LONG_MAX, which is at least 231-1, then you're going to have problems (undefined behavior that will probably show up as the value wrapping around).

Whether setting it to a value less than 0, or greater than or equal to one billion, will cause a problem depends on what you do with it. If you just want to print it, or perform some calculations on it, any valid long value should be ok -- but the stored values are probably more useful if you normalize them.

clock_gettime() should always give you a tv_nsec value in the range 0..999999999.

POSIX requires the clock_settime(), clock_nanosleep(), and nanosleep() functions to fail, and set errno to EINVAL, if "The tp argument specified a nanosecond value less than zero or greater than or equal to 1000 million."

References:

http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_settime.html http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_nanosleep.html http://pubs.opengroup.org/onlinepubs/9699919799/functions/nanosleep.html

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • 1
    +1. But it's worth explaining _how_ to do this. If you want to be completely POSIX/C portable, you have to check for overflow in advance of the addition, etc., which is no fun. If you just want to work on every practical POSIX platform (and aren't ever adding a denormalized timespec or more than 1G nanos), you can make the usual assumptions about how `long` works, which is pretty simple. If you only care about linux, you can use `timespec_add_safe`/`timespec_add` or `set_normalized_timespec`, which do all of it for you. – abarnert Jun 14 '13 at 18:50
  • @Keith Thompson I've followed your link to the posix std. It looks like the POSIX garantee you're talking about is defined for clock_settime(). "The clock_settime() function shall fail if:" . Or did I miss something? Because actually I am interested in such a garantee! :-) – yves Baumes Jan 19 '15 at 16:40
  • @yvesBaumes: I've just cleaned up my answer a bit. What guarantee are you asking about? – Keith Thompson Jan 19 '15 at 20:43
  • 1
    @KeithThompson I was talking about that assertion "clock_gettime() should always give you a tv_nsec value in the range 0..999999999". But I asked a dedicated question then : http://stackoverflow.com/questions/28029624/when-invoking-clock-gettime-may-the-returned-tv-nsec-field-actually-exceed-a-s – yves Baumes Jan 20 '15 at 12:32
1

A tv_nsec field will tolerate a limited amount of nanosecond overflow (always enough to add two valid timespec nanosecond values, so, 999999999 + 999999999 = 1999999998). There is no guarantee that an arbitrary amount of overflow will work, though: on implementations with 32-bit long, you can only go up to just over two seconds' worth of nanoseconds, to 2.147483647 seconds. So if someone tells you to add 2500 milliseconds (2.5 seconds), that would overflow.

Edit to add: and, as Keith Thompson notes, you need to re-normalize after adding one timespec to another.

torek
  • 448,244
  • 59
  • 642
  • 775