6

我正在编写一些将在多个互通系统上运行的代码。我使用 time() 来获取 time_t,但这会导致系统之间的时区差异出现问题,所以我想在 GMT 中获取 time_t。我一直在查看 time.h 函数,但我不清楚如何确定我会正确获得时间。到目前为止,这是我想出的:

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

现在,这似乎在我的机器上得到了正确的答案,但我想知道它是否会在我推出之前普遍工作,即使其他机器的时钟设置为当地时间或格林威治标准时间或不同时区或其他什么. 我担心的原因是mktime。在描述中,它说它将 tm 结构解释为“以本地时间表示的日历时间”。在我看来,它不会返回 GMT 时间,尽管它似乎在我的机器上。另外,当我打印出 gt 时,它比 t 提前 4 小时,这似乎是正确的。但是,如果我运行以下命令:

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

时间是一样的,都是当地时间,这不是我所期望的。

作为记录,在另一个答案中,我看到了对 timegm() 的引用,这听起来很完美,但它在我的系统上不存在。

简而言之,我如何在 C 语言的任何 Windows 机器上获得 GMT 的 time_t?

编辑:删除了添加的 msvcrt 标记,因为我没有使用 msvcrt。

4

4 回答 4

6

根据定义,time_t 始终采用 UTC。所以 time() 做你想做的事。只有在 time_t 和细分时间表示之间进行转换时,时区才会发挥作用。

如果您有 UTC 时间的分解时间表示,则需要临时将时区切换为 UTC,使用 mktime() 转换为 time_t,然后将时区切换回来,如下所示:

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;
}
于 2012-08-02T21:11:34.850 回答
3

查看代码的第一部分:

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

您设置gt为虚假值。调用时mktime,需要传入struct tm*当地时间。time_t定义为自 1970 年 1 月 1 日 00:00 UTC 以来的秒数。除非您当前处于 +0000 时区,否则您调用的返回值mktime将代表过去或未来几个小时的某个时间。

至于第二部分:

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

我认为gmtime并且localtime在内存中返回相同的缓冲区,这可能就是为什么你在输出中得到相同的两个小时。第二个调用覆盖第一个调用的输出。试试这个:

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);
于 2012-08-03T00:01:48.607 回答
2

使用gmtime()您想要的格林威治标准时间数字。localtime将报告本地时区的时间,并且仅当本地时区也是 GMT 时才会以 GMT 为准。

Windows 有自己的代码和数据结构来处理时间和时区。要使用 Windows 特定的 c 代码获取 GMT,您可以使用GetSystemTime(). 您可以在此 URL 上找到有关它的更多信息:http: //msdn.microsoft.com/en-us/library/windows/desktop/ms724390 (v=vs.85).aspx

请注意,Windows 使用自己的日期/时间结构,但在GetSystemTime()及其相关页面中也有详细说明。简而言之,GetSystemTime()检索当前系统日期和时间,以协调世界时 (UTC)(也称为 GMT)表示。它使用 Windows 结构 SYSTEMTIME,这是一个具有许多时间元素的结构。

于 2012-08-02T21:06:04.093 回答
0

请注意,对于这种微不足道的转换,您可以使用自己的函数。这里有一份mkgmtime()

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

这允许您将 a 转换为struct tm忽略time_t任何时区信息的值。不包括注释,这可能少于 100 行代码,因此很容易将其添加到您的项目中。

于 2014-12-02T08:24:03.777 回答