How do I get time_t in GMT on Windows in C

邮差的信 提交于 2019-12-10 07:54:55

问题


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.


回答1:


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;
}



回答2:


Use gmtime() as you want your time figure in GMT. localtime will report the time in the local time zone, and will only by GMT when the local time zone is also GMT.

Windows has its own code and data structures for dealing with time and time zones. To get GMT using windows specific c code, you can use GetSystemTime(). You can find more information about it at this URL: http://msdn.microsoft.com/en-us/library/windows/desktop/ms724390(v=vs.85).aspx

Please note that Windows uses its own date/time structure, but that is also detailed with the GetSystemTime() and its related pages. In short, GetSystemTime() retrieves the current system date and time, expressed in Coordinated Universal Time (UTC) (also known as GMT). It uses the Windows structure SYSTEMTIME which is a structure with many elements of time.




回答3:


Looking at the first part of your code:

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

You're setting gt to a bogus value. When calling mktime, you need to pass in a struct tm* that is in local time. time_t is defined as the number of seconds since January 1, 1970, 00:00 UTC. Unless you're currently in the +0000 time zone, the return value from your call to mktime will represent some time a few hours in the past or future.

As for the second part:

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

I think gmtime and localtime are returning the same buffer in memory, which might be why you're getting the same two hours in your output. The second call is overwriting the output of the first. Try this instead:

struct tm gtm, ltm;
struct tm *tm_buf;
time_t t = time();
tm_buf = gmtime(&t);
memcpy(&gtm, tm_buf, sizeof(struct tm));
tm_buf = localtime(&t);
memcpy(&ltm, tm_buf, sizeof(struct tm));
printf("%d, %d\n", gtm.tm_hour, ltm.tm_hour);



回答4:


Note that for such a trivial conversion, you can use your own function. There is a copy here of the mkgmtime()

https://github.com/m2osw/snapcpp/blob/master/snapwebsites/libsnapwebsites/src/snapwebsites/mkgmtime.c

This allows you to convert a struct tm to a time_t value ignoring any timezone information. Not including the comments, this is probably less than 100 lines of code, so very easy to add it to your project.



来源:https://stackoverflow.com/questions/11785272/how-do-i-get-time-t-in-gmt-on-windows-in-c

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!