views:

125

answers:

5

Okay so I would like to do some time stamping down to uS ... mS would be okay too ... but in looking into this, I am thinking What are the BEST PRACTICES when doing time stamping? My assumptions in this case are that C/C++ code is being used. I know internal clocks have various resolutions and the like ... but I am interested in things to be mindful about ... such answers will help with what I might not already know.

What should a good time format look like? What are your thoughts on Posix time functions? I want to have a textural representation and an internal representation? What is the easiest way to do this so times can be easily added and subtracted?

+1  A: 

In my opinion, the best approach is to keep an epoch based representation as an integer. The most standard one is to maintain seconds since 1970. Since you want to keep a higher resolution, you could extend this and keep microseconds or milliseconds since 1970. In order to accomplish this, you would need to use at least a 64 bit integer (long long).

The posix gettimeofday() will give you resolution up to microseconds and you can combine this with the gmtime_r() function to get the rest of the stamp. For windows, I use the GetSystemTime() function to get time in resolution up to milli-seconds (actually, I think that it is tens of milliseconds). The following code fragment shows this approach (not that my time units are nanoseconds).

  LgrDate rtn;
#ifdef _WIN32
  SYSTEMTIME sys;
  GetSystemTime(&sys);
  rtn.setDate(
     sys.wYear,
     sys.wMonth,
     sys.wDay);
  rtn.setTime(
     sys.wHour,
     sys.wMinute,
     sys.wSecond,
     sys.wMilliseconds*uint4(nsecPerMSec));
#else
  struct timeval time_of_day;
  struct tm broken_down;
  gettimeofday(&time_of_day,0);
  gmtime_r(
     &time_of_day.tv_sec,
     &broken_down);
  rtn.setDate(
     broken_down.tm_year + 1900,
     broken_down.tm_mon + 1,
     broken_down.tm_mday);
  rtn.setTime(
     broken_down.tm_hour,
     broken_down.tm_min,
     broken_down.tm_sec,
     time_of_day.tv_usec * nsecPerUSec);
#endif
  return rtn;
Jon Trauntvein
A: 

See your man page for gettimeofday

int gettimeofday(struct timeval *tp, void *);

long    tv_sec;    /* seconds since Jan. 1, 1970 */
     long    tv_usec;   /* and microseconds */

you can store times as a struct timeval, there are macros for doing addition & subtraction with struct timeval values. You can use ctime( tv_sec) to get an ascii string. If you need to create a string with usec try something like this:

char *now(void)  /* time to /1000ths of a second */
{
    struct timeval tv={0,0};
    int i=gettimeofday(&tv, NULL);
    static char retval[64]={0x0};
    char tmp[16]={0x0};

    if(i<0)
        return NULL;
    sprintf(tmp, "%.3f", (double)tv.tv_usec / (double)1000000);
    strftime(retval, sizeof(retval),
             "%Y-%m-%d %H:%M:%S.",
             localtime(&tv.tv_sec));
    strcat(retval, &tmp[2]);

    return retval;
}
jim mcnamara
A: 

There are no portable time functions that reliably give you resolution better than 10 ms. The function gettimeofday() referenced by other responders has a system-dependent resolution, which is, I believe, usually 1 or 10 ms. Furthermore, even 90% of non-portable time functions will involve a trip to ring 0 (thousands of clockticks), which means that it can take you 1-2 uS simply to execute the function call!

The only method that works on all Intel platforms, gives you sub-microsecond resolution, and costs less than 10 nanoseconds per call is the assembly instruction 'rdtsc' (or the intrinsic __rdtsc() ).

What is the format of the time returned by this function?
Xofo
a 64-bit integer.
rdtsc has lots of potential problems. On multi-CPU/multicore the TSC may be different for each core. The TSC may change frequency during CPU frequency changes. It may contain random values after suspend/resume ... See also this http://stackoverflow.com/questions/3835111/whats-the-most-accurate-way-of-measuring-elapsed-time-in-a-modern-pc/3835149#3835149
ninjalj
On Windows the clock ticks are often documented as being in the 10ms to 16ms range, though 15.6-something is common. rdtsc has the issues ninjalj describes, but for a fixed-clock server environment it can be combined with CPUID and measurements of core mis-sync to correlate the cores.
Tony
+1  A: 

Things to be mindful about?

Keep your systems synchronized via NTP, that way you can correlate logs from several systems.

If you store a timestamp internally, store it as number of seconds (possibly with decimals for mS or uS) since 1970 UTC. It's pretty standard, and on representation you can easily convert it to local time on any timezone (useful if you must deal with several timezones). Also, UTC has no daylight saving, which avoids some ambiguities (but not others, there are still leap seconds).

If you just want your timestamps for a log file, you can write the timestamp already converted to some human readable format. UTC still has its advantages here when dealing with multiple timezones and for avoiding daylight saving time ambiguities.

If you need something more exact, consider DJB's libtai, or, depending on your needs, POSIX clock_gettime() with CLOCK_MONOTONIC may suffice.

ninjalj
A: 

The new C++0x, among its various improvements, finally brings a full-fledged time library.

It has been developed primarily for thread support (to express duration / time limits for the various try_lock and al), but it's a real shiny pearl. You can find the original proposal here and Bjarne's entry about it here.

Obviously, it relies on your system being correctly synchronized if you wish to compare this time against external sources: use NTP. I would also recommend using UTC time, it's easier to express all times in a common timezone, without daylight saving.

As for the representation itself, I would go for human readable. It's about as easy for a machine to parse either format, but not so for a human, and who's investigating ?

[1] 2010/10/07 06:54:36.123456
[2] 2010 OCT 07 06:54:36.123456
[3] 86456156456.123456          // garbage I made up ;)

The second format allow to disambiguate the month from the day without any possible confusion. That's my favorite one, but I have most often see the first.

Matthieu M.