Retrieving system time: gettimeofday()

Some time ago, a friend of mine reported a problem with gettimeofday() under MinGW. It was a relatively common error: 'gettimeofday' undeclared (first use this function). Cause and solution of this problem is kind of easy, and we’ll present it at the end of the post. However, what’s that function gettimeofday()?

gettimeofday() is a function for retrieving system time in POSIX-compliant systems. Unlike the time() function, which has a resolution of 1 second, gettimeofday() has a higher resolution: microseconds. Specifically, the prototype of gettimeofday() is:

int gettimeofday (struct timeval *tp, struct timezone *tzp)

The function retrieves the current time expressed as seconds and microseconds since the Epoch, and stores it in the timeval structure pointed to by tp. The struct timeval has the following members:

long int tv_sec: Number of whole seconds of elapsed time.
long int tv_usec: The rest of the elapsed time (a fraction of a second), represented as the number of microseconds.

Thanks to the tv_usec member, we have a resolution of microseconds. It’s also important to remember what the Epoch is. The Epoch is just an arbitrary starting date set by the system in order to compute time, i.e., it’s a reference or base time. For instance, POSIX-compliant systems measure system time as the number of seconds elapsed since the start of the epoch at 1970-01-01 00:00:00 Z.

On its side, the struct timezone was used to return information about the time zone. However, using this parameter is obsolete (e.g., it has not been and will not be supported by libc or glibc). Therefore, tzp should be a null pointer, else the behavior may be unspecified (check your system’s specifications).

gettimeofday() returns 0 for success, or -1 for fail. Simple. Further, this function should be available in sys/time.h. But my friend’s installation of MinGW only included the following in sys/time.h:

#include <windows.h>

#ifndef _TIMEVAL_DEFINED /* also in winsock[2].h */
struct timeval {
  long tv_sec;
  long tv_usec;
#define timerisset(tvp)	 ((tvp)->tv_sec || (tvp)->tv_usec)
#define timercmp(tvp, uvp, cmp) \
	(((tvp)->tv_sec != (uvp)->tv_sec) ? \
	((tvp)->tv_sec cmp (uvp)->tv_sec) : \
	((tvp)->tv_usec cmp (uvp)->tv_usec))
#define timerclear(tvp)	 (tvp)->tv_sec = (tvp)->tv_usec = 0
#endif /* _TIMEVAL_DEFINED */

No gettimeofday(). That’s why gcc complained. For solving it, just update your MinGW setup, or alternatively we can define gettimeofday() as a wrapper around GetSystemTimeAsFileTime(), which is the function for retrieving system time in Windows. GetSystemTimeAsFileTime() has a resolution of 100 nanoseconds. Basically, you have to append the following to the original sys/time.h:

/* Provided for compatibility with code that assumes that
   the presence of gettimeofday function implies a definition
   of struct timezone. */
struct timezone
  int tz_minuteswest; /* of Greenwich */
  int tz_dsttime;     /* type of dst correction to apply */

   Implementation as per:
   The Open Group Base Specifications, Issue 6
   IEEE Std 1003.1, 2004 Edition

   The timezone pointer arg is ignored.  Errors are ignored.

#ifdef	__cplusplus

void  GetSystemTimeAsFileTime(FILETIME*);

inline int gettimeofday(struct timeval* p, void* tz /* IGNORED */)
	union {
	    long long ns100; /*time since 1 Jan 1601 in 100ns units */
	} now;

    GetSystemTimeAsFileTime( &(now.ft) );
    p->tv_usec=(long)((now.ns100 / 10LL) % 1000000LL );
    p->tv_sec= (long)((now.ns100-(116444736000000000LL))/10000000LL);
	return 0;

    /* Must be defined somewhere else */
	int gettimeofday(struct timeval* p, void* tz /* IGNORED */);

Finally, an interesting remark. My friend uses gettimeofday() to initialize srand(). The most common initialization one finds in books and Internet is srand((unsigned)time(0)), but that’s a rather poor initialization. Do you want details? Read this excellent explanation by Christian Stigen Larsen: Never use time() to initialize srand().

7 thoughts on “Retrieving system time: gettimeofday()”

  1. @mini_man_80: Yes, that’s the “form” we find everywhere. And indeed it just work. However, I recommend to read what Christian Stigen Larsen points out about this matter. He even offers an interesting remark:

    “Most people that do (or try, like me) to do serious programming nowadays will not use rand().”

    A nice reading. I recommend it.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.