【问题标题】:Converting string containing localtime into UTC in C在C中将包含本地时间的字符串转换为UTC
【发布时间】:2010-12-18 09:27:09
【问题描述】:

我有一个包含本地日期/时间的字符串,我需要将其转换为 time_t 值(以 UTC 为单位) - 我一直在尝试这个:

char* date = "2009/09/01/00";
struct tm cal = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL};
strptime(date, "%Y/%m/%d/%H", &cal);
time_t t = mktime(&cal);

但是如果字符串被解析为 UTC 而不是本地时间,我得到的 time_t 值是我期望的值。也许我误解了 strptime 应该做什么,但是在 9 月 1 日我的时区(英国)中,我们使用的是 BST(即 UTC + 1 小时),所以我希望我最终得到的值比 UTC 早 1 小时.

有没有办法将字符串解释为本地时间,自动考虑在该日期生效的 UTC 偏移量?请注意,我需要 time_t 值而不是 struct tm,在上面的示例中,我希望 time_t 值对应于 2009-09-01 01:00:00 GMT

【问题讨论】:

    标签: c datetime parsing date utc


    【解决方案1】:

    您可以使用mktime 来解释本地时区中的 struct tm。这样做时,请小心设置tm_isdst 标志。夏季为 0,冬季为 1,为 -1 让mktime 弄清楚。下面是一些示例代码:

    void main()
    {
        char* date = "2009/09/01/00";
        struct tm cal = {};
        // Read string into struct tm
        strptime(date, "%Y/%m/%d/%H", &cal);
        // Tell mktime to figure out the daylight saving time
        cal.tm_isdst = -1;
        printf("%20s: %s", "Before mktime", asctime(&cal));
        // Convert struct tm to time_t
        time_t t = mktime(&cal);
        // Convert time_t to localtime
        struct tm localcal = *localtime(&t);
        printf("%20s: %s", "Local time", asctime(&localcal));
        printf("%20s: %i\n", "Local DST", localcal.tm_isdst);
        // Convert time_t to GMT
        struct tm gmcal = *gmtime(&t);
        printf("%20s: %s", "GM time", asctime(&gmcal));
        printf("%20s: %i\n", "GM DST", gmcal.tm_isdst);
    }
    

    打印出来(我住在 GMT+1,现在是冬天):

       Before mktime: Tue Sep  1 00:00:00 2009
          Local time: Tue Sep  1 00:00:00 2009
           Local DST: 1
             GM time: Mon Aug 31 22:00:00 2009
              GM DST: 0
    

    看起来mktime 根据当前夏令时转换了 9 月的日期。现在是十一月,所以实际上是一个小时的休息时间。我还没有找到纠正的方法。

    【讨论】:

    • 谢谢,但它是我感兴趣的 time_t 值 - 如果我在代码中的 'localcal' 结构上执行 mktime() ,它给我的结果与在上执行 mktime() 相同'卡尔'。我需要一些方法来产生一个相当于“2009-09-01 01:00 GMT”的 time_t 值
    • C 约定将 time_t 存储为自 1970 年 1 月 1 日以来的 UTC 秒数。将其更改为 localtime 仅用于解释或显示。如果您想引入 rob_t 作为 localtime 变量,您可以计算 gmtime() 和 localtime() 之间的秒数并将其添加到您的 time_t 中。 :)
    • 好的,但我想将字符串解释为本地时间,而不是生成与 UTC 时间字符串等效的本地时间。在我们的例子中,假设我们生活在 GMT+1,字符串“2009/09/01/00”是我们的当地时间,所以它相当于 GMT 的“2009/09/01/01”,所以代码应返回与“2009/09/01/01”对应的 time_t 值。这有意义吗?
    • 对,这东西很复杂。原来mktime() 确实期望一个本地时间结构。我的示例中的 1 小时差异是夏令时,在 cal 中设置为 0,但目前为 1。我将编辑示例。
    • 如果您不希望转换为本地时间,您可以使用mktime 的UTC 等效值,即timegm
    【解决方案2】:

    这是我的版本,使用 tm_gmtoff。希望图书馆能照顾夏时制......

    #define _BSD_SOURCE
    #define _XOPEN_SOURCE
    #include <stdio.h>
    #include <time.h>
    
    int gmtoffset(void) {
      struct tm *dummy;
      time_t t = 0;
      dummy = localtime(&t);
      return dummy->tm_gmtoff; /* _BSD_SOURCE */
    }
    
    int main(void) {
      int off;
      const char *date = "2009/09/01/00";
      struct tm cal = {0};
      time_t t;
    
      off = gmtoffset();
    
      strptime(date, "%Y/%m/%d/%H", &cal); /* _XOPEN_SOURCE */
      t = mktime(&cal);
      printf("t     --> %s", ctime(&t)); /* ctime includes a final '\n' */
      t -= off;
      printf("t-off --> %s", ctime(&t));
      return 0;
    }
    
    $ /usr/bin/gcc ptime.c $ ./a.out t --> 2009 年 9 月 1 日星期二 01:00:00 t-off --> 2009 年 9 月 1 日星期二 00:00:00

    【讨论】:

    • 您传递给mktimestruct tmtm_isdst 设置为0,因此在没有夏令时的情况下读取时间。然后将它传递给ctime,它通过增加 1 小时来纠正 DST。接下来,减去偏移量,这也是令人困惑的 1 小时,以获得一些随机时间。这些东西让我头晕目眩,但我想深入了解它:)
    • 这个夏令时很有趣。我刚刚意识到 DST 目前没有生效,但它是在 9 月 1 日!嗯......我想图书馆无法“知道” DST 何时开始和结束于特定位置。我认为您必须手动管理 DST (timeanddate.com/time/dst2009.html)
    【解决方案3】:

    感谢 Andomar,我想我现在已经破解了 - 此代码可以满足我的需要,并且无论当前的 DST 状态如何,它似乎都能正常工作(我更改了我的 PC 上的时钟以检查这一点):

    #include <time.h>
    #include <assert.h>
    
    time_t parseLocalDate(char* date){
        struct tm cal = {0, 0, 0, 0, 0, 0, 0, 0, -1, 0, NULL};
        strptime(date, "%Y/%m/%d/%H", &cal);
        return mktime(&cal);
    }
    
    int main(int argc, char *argv[]){
     // DST is effect, Local Time = GMT+1
        assert(1251759600 == parseLocalDate("2009/09/01/00")); // Mon, 31 Aug 2009 23:00:00 GMT
        assert(1254351600 == parseLocalDate("2009/10/01/00")); // Wed, 30 Sep 2009 23:00:00 GMT
     // DST not in effect, Local Time = GMT
        assert(1257033600 == parseLocalDate("2009/11/01/00")); // Sun, 01 Nov 2009 00:00:00 GMT
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-09
      • 1970-01-01
      • 2014-12-10
      • 2011-06-13
      • 2020-11-22
      • 2014-02-04
      • 2018-02-23
      • 2016-10-03
      相关资源
      最近更新 更多