【问题标题】:Converting between timezones in C在 C 中的时区之间转换
【发布时间】:2009-07-23 18:19:51
【问题描述】:

我需要在 C 中的时区之间转换时间(在 linux 上,所以任何特定的东西也可以)。

我知道我的当前时间,本地时间和UTC,我有目标时间的偏移量。我正在尝试使用 mktime、gmtime、localtime 和类似的功能集,但仍然无法弄清楚。

提前致谢。

【问题讨论】:

    标签: c timezone


    【解决方案1】:

    由于 cmets 不允许发布代码,因此作为单独的答案发布。如果您知道“本地”时间和“UTC”时间,则可以计算“其他”时间与“本地”时间的偏移量。然后将 struct tm 转换为日历时间,添加所需的秒数(即目标时间的偏移量),并将其转换回 struct tm:

    (编辑以考虑使用 mktime 标准化的另一种情况)

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <sys/time.h>
    
    int main(int argc, char *argv) {
      struct timeval tv_utc;
      struct tm *local_tm, *other_tm;
    
      /* 'synthetic' time_t to convert to struct tm for the other time */
      time_t other_t_synt;
      /* Other time is 1 hour ahead of local time */
      int other_local_delta = 1*3600; 
    
    
      /* the below two lines are just to set local_tm to something */
      gettimeofday(&tv_utc, NULL);
      local_tm = localtime(&tv_utc.tv_sec);
    
      printf("Local time: %s", asctime(local_tm));
    
      #ifdef DO_NOT_WRITE_TO_LOCAL_TM
      other_t_synt = mktime(local_tm) + other_local_delta;
      #else
      local_tm->tm_sec += other_local_delta;
      /* mktime will normalize the seconds to a correct calendar date */
      other_t_synt = mktime(local_tm);
      #endif
    
      other_tm = localtime(&other_t_synt);
    
      printf("Other time: %s", asctime(other_tm));
    
      exit(0);
    }
    

    【讨论】:

    • 这似乎运作良好。我将使用 local_tm->tm_sec += 3600; other_t = mktime(local_tm);而是让 mktime 为我做所有的标准化工作。
    • 是的,这应该也可以——我试图保持礼貌,避免写在别人的内存上,因为本例中 local_tm 指向的内存不属于我的代码。
    • 无论如何,自动标准化是一件好事,我也根据您的使用情况编辑了示例。我认为一旦您添加其他时间和您的时间之间的增量,这种情况下的“纪元”时间 other_t 将是合成的,因此我也相应地对其进行了重命名。
    • 这假设我们知道当前和其他之间的增量。或者UCT和其他也可以。但是该增量不一定在一年中保持不变(DST 在各个国家/地区开始/结束,甚至更改特定区域的本地时间转换规则)。对于任意 Unix 纪元值,是否有一种通用方法可以将区域 A 转换为区域 B?
    • 我认为您可以设置环境变量“TZ”,然后使用 tzset 来“假装”您的本地时间在 A 区或 B 区。这是唯一或多或少的“通用”方法我会想到的。
    【解决方案2】:

    如果你知道偏移量,你可以使用 gmtime() 和 tm 结构直接设置它。

    如果您知道您的本地时间和 UTC,您就知道您的本地偏移量。如果您还知道目标偏移量,只需设置适当的 tm_hour(如果您选择 23,也可能会翻转一天)。

    有关一些示例代码,请参阅此gmtime reference page。它显示了基于时区偏移量的偏移量。


    编辑:

    作为对 cme​​ts 的响应 - 您还可以让 mktime 为您处理移位,这使您可以通过转换回 time_t 来简化此操作。你可以使用类似的东西:

    time_t currentTime;
    tm * ptm;
    time ( &currentTime );
    ptm = gmtime ( &rawtime );
    ptm->tm_hour += hours_to_shift;
    ptm->tm_minutes += minutes_to_shift; // Handle .5 hr timezones this way
    
    time_t shiftedTime = mktime( ptm );
    // If you want to go back to a tm structure:
    
    tm * pShiftedTm = gmtime( &shiftedTime );
    

    【讨论】:

    • FWIW,不仅是 tm_hour - 例如印度标准时间 (IST) 是 UTC+5.5
    • 是的,是的。您必须潜在地操纵几乎所有领域,但这个概念是合理的。
    • 其实,我认为有一种方法可以避免手动进行过多的算术运算...由于 cmets 不允许代码,我将其作为另一个答案发布。
    • hmm .. 我阅读了 mktime 上的参考页面,其中说如果我修改 tm 结构,我可以使用 mktime 来标准化时间。所以这将负责标准化日期,否则它可能会变得复杂。然后我可能想将这个时间转换回 tm 结构(我不知道我应该使用 localtime 还是 gmtime),以便我可以使用 strftime 等函数来获取格式化的时间值。
    【解决方案3】:

    您的操作系统很可能为此提供了一些支持。

    在 unix 派生的操作系统中,您可能需要查看 asctime, asctime_r, ctime, ctime_r, difftime, gmtime, gmtime_r, localtime, localtime_r, mktime, timegm 的手册页。

    【讨论】:

    • 您提到的 Posix API 并没有真正提供一种明显的方式来解决问题。这些问题已经按名称提到了其中一些函数,因此再次提及它们并指向手册页基本上不太可能是一个有用的答案。
    猜你喜欢
    • 2017-03-05
    • 2013-05-08
    • 1970-01-01
    • 1970-01-01
    • 2016-11-06
    • 2018-06-12
    • 2011-07-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多