c - 如何在 C 中将 UTC 时间转换为本地时间?

标签 c time posix utc datetime-conversion

这是一个简单的问题,但解决方案似乎远非简单。我想知道如何将 UTC 时间转换为本地时间。我正在寻找一种标准的 C 语言解决方案,并且或多或少可以保证在任何位置的任何计算机上工作。

我已经仔细阅读了以下链接,但在那里找不到解决方案:

Converting string containing localtime into UTC in C

Converting Between Local Times and GMT/UTC in C/C++

我尝试了多种变体,例如(datetime 是一个包含 UTC 时间和日期的字符串):

strptime(datetime, "%A %B %d %Y %H %M %S", tp);
strftime(printtime, strlen(datetime), "%A %B %d %Y %H %M %S", tp);

或者

strptime(datetime, "%A %B %d %Y %H %M %S", tp);
lt=mktime(tp);
printtime=ctime(&lt);

无论我尝试什么,打印时间最终都与 UTC 相同。

编辑 11-29-2013:基于下面“R”的非常有帮助的回答,我终于开始创建一个工作示例。我发现它在我测试的两个时区 CET 和 PST 中工作正常:

#include <time.h>
#include <stdio.h>
#include <stdlib.h>

long long diff_tm(struct tm *a, struct tm *b)
{
  return a->tm_sec - b->tm_sec
          +60LL*(a->tm_min - b->tm_min)
          +3600LL*(a->tm_hour - b->tm_hour)
          +86400LL*(a->tm_yday - b->tm_yday)
          +(a->tm_year-70)*31536000LL
          -(a->tm_year-69)/4*86400LL
          +(a->tm_year-1)/100*86400LL
          -(a->tm_year+299)/400*86400LL
          -(b->tm_year-70)*31536000LL
          +(b->tm_year-69)/4*86400LL
          -(b->tm_year-1)/100*86400LL
          +(b->tm_year+299)/400*86400LL;
}


int main()
{
  time_t utc, local;
  char buf[100];
  const char datetime[]="2013 11 30 23 30 26 UTC"; /* hard coded date and time in UTC */

  struct tm *tp=malloc(sizeof(struct tm));
  if(tp==NULL)
    exit(-1);

  struct tm *localt=malloc(sizeof(struct tm));
  if(localt==NULL)
    exit(-1);

  memset(tp, 0, sizeof(struct tm));
  memset(localt, 0, sizeof(struct tm));

  printf("UTC date and time to be converted in local time: %s\n", datetime);

  /* put values of datetime into time structure *tp */
  strptime(datetime, "%Y %m %d %H %M %S %z", tp);

  /* get seconds since EPOCH for this time */
  utc=mktime(tp);
  printf("UTC date and time in seconds since EPOCH: %d\n", utc);

  /* lets convert this UTC date and time to local date and time */

  struct tm e0={ .tm_year = 70, .tm_mday = 1 }, e1, new;
  /* get time_t EPOCH value for e0 (Jan. 1, 1970) */
  time_t pseudo=mktime(&e0);

  /* get gmtime for this value */
  e1=*gmtime(&pseudo);

  /* calculate local time in seconds since EPOCH */
  e0.tm_sec += utc - diff_tm(&e1, &e0);

  /* assign to local, this can all can be coded shorter but I attempted to increase clarity */
  local=e0.tm_sec;
  printf("local date and time in seconds since EPOCH: %d\n", local);

  /* convert seconds since EPOCH for local time into localt time structure */
  localt=localtime(&local);

  /* get nicely formatted human readable time */
  strftime(buf, sizeof buf, "%Y-%m-%d %H:%M:%S %Z", localt);

  printf("local date and time: %s\n", buf);
}

它应该可以在大多数系统上正常编译。我用 UTC 硬编码时间和日期,然后将其转换为本地时间和日期。

最佳答案

如果您可以假设 POSIX(因此 time_t 的 POSIX 规范为自纪元以来的秒数),我将首先使用 POSIX 公式转换为自纪元以来的秒数:

tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
    (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
    ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400

接下来,使用 localtime((time_t []){0}) 获取表示本地时间纪元的 struct tm。将纪元以来的秒数添加到此 struct tmtm_sec 字段,然后调用 mktime 对其进行规范化。

编辑: 实际上,唯一的 POSIX 依赖项是有一个已知的时代,它对应于 (time_t)0。也许你可以找到解决方法,如果你真的需要...例如,在 time_t 0 时调用 gmtimelocaltime。 .

编辑 2:如何执行此操作的草图:

#include <time.h>
#include <stdio.h>

long long diff_tm(struct tm *a, struct tm *b)
{
        return a->tm_sec - b->tm_sec
                +60LL*(a->tm_min - b->tm_min)
                +3600LL*(a->tm_hour - b->tm_hour)
                +86400LL*(a->tm_yday - b->tm_yday)
                +(a->tm_year-70)*31536000LL
                -(a->tm_year-69)/4*86400LL
                +(a->tm_year-1)/100*86400LL
                -(a->tm_year+299)/400*86400LL
                -(b->tm_year-70)*31536000LL
                +(b->tm_year-69)/4*86400LL
                -(b->tm_year-1)/100*86400LL
                +(b->tm_year+299)/400*86400LL;
}

int main(int argc, char **argv)
{
        char buf[100];
        struct tm e0 = { .tm_year = 70, .tm_mday = 1 }, e1, new;
        time_t pseudo = mktime(&e0);
        e1 = *gmtime(&pseudo);
        e0.tm_sec += atoi(argv[1]) - diff_tm(&e1, &e0);
        mktime(&e0);
        strftime(buf, sizeof buf, "%c", &e0);
        puts(buf);
}

请不要介意丑陋的输出代码。该程序采用“相对于 POSIX 纪元的秒数​​”形式的参数,并以本地时间输出结果时间。您可以使用我上面引用的公式将任何 UTC 时间转换为自纪元以来的秒数。请注意,此代码不以任何方式依赖于 POSIX,但它确实假设 diff_tm 返回的偏移量与 seconds-since-the-epoch 值相结合不会溢出 int。解决此问题的方法是使用 long long 偏移量和一个不断添加不大于 INT_MAX/2(或小于 INT_MIN/2)的增量的循环 并调用 mktime 重新归一化,直到偏移量达到 0。

关于c - 如何在 C 中将 UTC 时间转换为本地时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9076494/

相关文章:

c - 在使用 nostdlib 和 nostdinc 标志进行编译时如何使用 stdio 和 stdlib?

algorithm - 部分排序序列的最佳排序算法?

CUDA 使用 cudaMemcpy2D 将数组从设备复制到主机

c - 如何增加链表中的指针

python - 用第一个值减去 Pandas 数据框中的一列

linux - 自定义信号不够用怎么办

c - POSIX C `warning: variable ‘tables’ 已设置但未使用`

linux - POSIX UDP 套接字 : how is the data splitted to UDP packets?

c++ - GCC中__attribute__((unused))和__attribute((unused))的区别

android - 像 Google Agenda App 这样的新 TimePicker 对话框