2

Since Mac OS X doesn't support get time, I found this gist that made a portable way to use the clock_gettime fund here:

void current_utc_time(struct timespec *ts) {

#ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time
    clock_serv_t cclock;
    mach_timespec_t mts;
    host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
    clock_get_time(cclock, &mts);
    mach_port_deallocate(mach_task_self(), cclock);
    ts->tv_sec = mts.tv_sec;
    ts->tv_nsec = mts.tv_nsec;
#else
  clock_gettime(CLOCK_REALTIME, ts);
#endif
}

using it like this

struct timespec requestStart;
current_utc_time(&requestStart);
printf("start: s:  %lu\n", requestStart.tv_sec);
printf("start: ns: %lu\n", requestStart.tv_nsec);
start: s:  1435988139
start: ns: 202015000

I am trying to get the seconds and milliseconds value from this code, is this the correct way to get milliseconds from the nanoseconds value?

printf("total: ms:  %lu\n", (requestStart.tv_nsec - requestEnd.tv_nsec) / (unsigned long)1000000);

If so, how do I get the seconds value? If not how can I get the milliseconds and seconds value?

edit In response to the first comment, I am mainly looking for a way to have the code as portable as possible.

mr oh
  • 93
  • 9
  • 1
    This is _so_ not ANSI C :-) In any case, the real standard is ISO, ANSI is just one of the feeder bodies into that nowadays. – paxdiablo Jul 04 '15 at 05:45
  • MacOS doesn't have a simple interface for getting the system time? That's pretty hard to believe! – wallyk Jul 04 '15 at 06:06
  • @wallyk as you can see from apples official docs I used the timer they provide in the function above. Here's the doc: https://developer.apple.com/library/ios/technotes/tn2169/_index.html I was more concerned about converting the nanoseconds to seconds and milliseconds from the above function. – mr oh Jul 04 '15 at 06:25
  • did you try to link with `-lrt`? **clock_gettime(3)** is a POSIX compliant function but in several architectures you have to link it or use the `#define _POSIX_SOURCE` macro to access it. – Luis Colorado Jul 05 '15 at 18:03

2 Answers2

2

If you want portability, just use gettimeofday. That should work everywhere. clock_gettime appears to be Linux-specific a relatively recent Posix introduction.

On converting: struct timeval (used by gettimeofday and other older functions) uses microseconds. The newer struct timespec uses nanoseconds. So to convert back and forth, you would multiply or divide by 1000.

When computing differences, you have to worry about carry/overflow, so your expression

(requestStart.tv_nsec - requestEnd.tv_nsec) / (unsigned long)1000000

is incorrect for two reasons: the difference might come out negative (that is, if the time went from 123.456 to 124.321), and you're scaling it by too much.

When I'm timing some operation, I usually do it something like this:

struct timeval before, after, elapsed;
gettimeofday(&before, NULL);
sleep(1);
gettimeofday(&after, NULL);
elapsed.tv_sec = after.tv_sec - before.tv_sec;
if(after.tv_usec >= before.tv_usec)
        elapsed.tv_usec = after.tv_usec - before.tv_usec;
else    {
        elapsed.tv_sec--;
        elapsed.tv_usec = 1000000 + after.tv_usec - before.tv_usec;
        }
printf("elapsed: %d.%06ld\n", (int)elapsed.tv_sec, (long)elapsed.tv_usec);

If I then wanted a struct timespec (using nanoseconds), I'd multiply by 1000:

struct timespec elapsed2;
elapsed2.tv_sec = elapsed.tv_sec;
elapsed2.tv_nsec = elapsed.tv_usec * 1000;
printf("elapsed: %d.%09ld\n", (int)elapsed2.tv_sec, (long)elapsed2.tv_nsec);

To convert from a struct timespec back to a struct timeval, I'd divide by 1000:

struct timeval elapsed3;
elapsed3.tv_sec = elapsed2.tv_sec;
elapsed3.tv_usec = elapsed2.tv_nsec / 1000;

Another useful thing is to pull out seconds and subseconds as floating point:

double e = (double)elapsed.tv_sec + elapsed.tv_usec / 1e6;
double e2 = (double)elapsed2.tv_sec + elapsed2.tv_nsec / 1e9;
printf("float: %f %f\n", e, e2);

(It turns out that there can be subtleties when writing this sort of code, depending on the actual types of tv_sec and tv_usec or tv_nsec, and on the "helpful" warnings your compiler might choose to give you. See this question.)

Community
  • 1
  • 1
Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • This is the most detailed answer I've seen and it's helped me so much. So you can convert from these different time structures. – mr oh Jul 04 '15 at 22:09
  • Minor: `printf("elapsed: %d.%09ld\n", (int)elapsed2.tv_sec, (long)elapsed2.tv_nsec);` `(long)` cast not needed as field `tv_nsec`is specified as `long`. Casting field `time_t tv_sec` to `int` can easily be a narrowing: Consider `"%lld", (long long) elapsed2.tv_sec` to avoid https://en.wikipedia.org/wiki/Year_2038_problem – chux - Reinstate Monica Jul 06 '15 at 18:29
0
#import <time.h>
#import <sys/timeb.h>

struct timeb timebCurrentTime;

ftime(&timebCurrentTime);
double y = (double)timebCurrentTime.time + (double)timebCurrentTime.millitm / 1000;//current time in sec since 1970-01-01 00:00:00 +0000 (UTC)
jdl
  • 6,151
  • 19
  • 83
  • 132