How do I get time_t in GMT on Windows in C

Derek picture Derek · Aug 2, 2012 · Viewed 14.9k times · Source

I am writing some code that will run on multiple intercommunicating systems. I was using time() to get time_t, but this was causing problems with time zone differences between the systems, so I want to get time_t in GMT. I've been looking through the time.h functions, but it is unclear to me how I can be sure that I will get the time correctly. This is what I've come up with so far:

time_t t = time();
struct tm *gtm = gmtime(&t);
time_t gt = mktime(gtm);

Now, this seems to get the correct answer on my machine, but I want to know if it will work universally before I push it out, even if the other machines' clocks are set to local time or GMT or in different time zones or whatever. The reason I am concerned is because of mktime. In the description, it says that it interprets the tm struct as "a calendar time expressed in local time." That sounds to me like it will not be returning the GMT time, though it seems to be on my machine. Also, when I print out gt, it is 4 hours ahead of t, which seems right. But if I run the following:

time_t t = time();
struct tm *gtm = gmtime(&t);
struct tm *ltm = localtime(&t);
printf("%d, %d\n", gtm->tm_hour, ltm->tm_hour);

the hours are the same and are local time, which is not what I expected.

For the record, in another answer, I saw reference to timegm(), which sounds perfect, but it does not exist on my system.

So in short, how do I get time_t in GMT on any Windows machine in C?

Edit: removed msvcrt tag that was added, as I am not using the msvcrt.

Answer

user1157391 picture user1157391 · Aug 2, 2012

time_t is always in UTC, by definition. So time() does what you want. Timezones only come into play when you are converting between time_t and broken-down time representation.

If you have the time in UTC in broken-down time representation, you need to temporarily switch the timezone to UTC, use mktime() to convert to a time_t, and switch the timezone back, like this:

time_t convert_utc_tm_to_time_t (struct tm *tm)
{
    char *tz;
    time_t result;

    /* temporarily set timezone to UTC for conversion */
    tz = getenv("TZ");
    if (tz) {
      tz = strdup (tz);
      if (!tz) {
        // out of memory
        return -1;
      }
    }
    setenv("TZ", "", 1);
    tzset();

    tm->tm_isidst = 0;
    result = mktime (tm);

    /* restore timezone */
    if (tz) {
      setenv("TZ", tz, 1);
      free (tz);
    }
    else {
      unsetenv("TZ");
    }
    tzset();

    return result;
}