Header image at HALCODE

Retrieving system time: gettimeofday()

August 26th, 2008  |  Published in C, Languages, Operating Systems, Programming  |  4 Comments

Today, 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 <time.h>
 
#ifndef _TIMEVAL_DEFINED /* also in winsock[2].h */
#define _TIMEVAL_DEFINED
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, we can define gettimeofday() as a wrapper around GetSystemTimeAsFileTime(), which is the function for retrieving system time in Windows (Windows 2000, XP and Vista). GetSystemTimeAsFileTime() has a resolution of 100 nanoseconds. The complete sys/time.h (and more details) can be found in this excellent page which explains how to build OpenBabel with MinGW. 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 */
		FILETIME ft;
	} now;
 
    GetSystemTimeAsFileTime( &(now.ft) );
    p->tv_usec=(long)((now.ns100 / 10LL) % 1000000LL );
    p->tv_sec= (long)((now.ns100-(116444736000000000LL))/10000000LL);
	return 0;
}
 
#else
    /* Must be defined somewhere else */
	int gettimeofday(struct timeval* p, void* tz /* IGNORED */);
#endif
 

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().

Thank you for reading!

Responses

  1. mini_man_80 says:

    August 26th, 2008at 11:43 pm(#)

    just use srand(time(NULL))

  2. Jose says:

    August 30th, 2008at 12:21 am(#)

    @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.

  3. leberwurst says:

    September 8th, 2009at 10:27 pm(#)

    … works excellent! … But don’t forget to

    #include

  4. leberwurst says:

    September 8th, 2009at 10:28 pm(#)

    #include windows.h

Leave a Response