如何从UTC转换为本地时间用C? [英] How to convert from UTC to local time in C?

查看:1129
本文介绍了如何从UTC转换为本地时间用C?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个简单的问题,但解决的办法似乎从简单的远。我想知道如何从UTC转换为本地时间。我期待在C这是标准或多或少保证在任何位置的任何计算机上工作的解决方案。

It's a simple question, but the solution appears to be far from simple. I would like to know how to convert from UTC to local time. I am looking for a solution in C that's standard and more or less guaranteed to work on any computer at any location.

我已经仔细阅读下面的链接,但我不能找到一个解决方案有:

I have read the following links carefully but I can't find a solution there:

<一个href=\"http://stackoverflow.com/questions/1764710/converting-string-containing-localtime-into-utc-in-c\">Converting含本地时间到UTC使用C 字符串

<一个href=\"http://stackoverflow.com/questions/761791/converting-between-local-times-and-gmt-utc-in-c-c\">Converting本地时间和GMT / UTC在C / C ++

我已经尝试了一些变化,如(日期时间是与UTC时间和日期的字符串):

I have tried a number of variations, such as (datetime is a string with time and date in 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);

不管是什么我尝试printtime最终是一样的UTC。

No matter what I try printtime ends up being the same as UTC.

修改2013年11月29日:基于R非常有用的答案下面我终于可以创建一个工作示例。我发现它在我测试过,CET和PST的两个时区是工作正确的:

Edit 11-29-2013: based on the very helpful answer by "R" below I finally got around to create a working example. I found it to be working correct in the two timezones I tested it, CET and 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);
}

应该没有编译在大多数系统上的问题。我很难$ C $的CD,然后将转换为本地时间和日期UTC时间和日期。

It should compile without problems on most systems. I hard coded a time and date in UTC which then will be converted to the local time and date.

推荐答案

如果你可以假设POSIX(因此从纪元 time_t的的POSIX规范为秒),我首先使用POSIX公式转换为秒,因为时代:

If you can assume POSIX (and thus the POSIX specification of time_t as seconds since the epoch), I would first use the POSIX formula to convert to seconds since the epoch:

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

下一步,使用本地时间((time_t的[]){0})获得结构TM 重新presenting在当地时间的时代。添加秒时代以来至本结构TM tm_sec 字段,然后调用 mktime 规范化它。

Next, use localtime((time_t []){0}) to get a struct tm representing the epoch in local time. Add the seconds since the epoch to the tm_sec field of this struct tm, then call mktime to canonicalize it.

编辑:其实唯一的POSIX依赖关系具有已知划时代其中(time_t的)0 对应。也许你可以找到周围的方式,如果你真的需要...例如使用到两个呼叫 gmtime的本地时间 time_t的 0 ..

Actually the only POSIX dependency is having a known epoch which (time_t)0 corresponds to. Perhaps you can find a way around that if you really need to... for instance using calls to both gmtime and localtime at time_t 0..

编辑2:如何做到这一点的草图:

Edit 2: A sketch of how to do this:

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

请不要介意丑陋输出code。该方案需要在秒相对于POSIX时代的形式参数,并在输出当地时间产生的时间。您可以通过我上面提到的任何公式UTC时间转换成秒以来的时代。请注意,这code不以任何方式依赖于POSIX,但它确实承担起 diff_tm 偏移返回结合秒 - 因为最划时代的价值呢不漫 INT 。针对此解决将是使用长长偏移和不断增加的增量不大于一个循环 INT_MAX / 2 (或小于 INT_MIN / 2)并调用 mktime 来重新规格化直到偏移达到0。

Please don't mind the ugly output code. This program takes an argument in the form of "seconds relative to the POSIX epoch" and outputs the resulting time in local time. You can convert any UTC time to seconds since the epoch using the formula I cited above. Note that this code does not in any way depend on POSIX, but it does assume the offset returned by diff_tm combined with the seconds-since-the-epoch value does not overflow int. A fix for this would be to use a long long offset and a loop that keeps adding increments no larger than INT_MAX/2 (or smaller than INT_MIN/2) and calling mktime to renormalize until the offset reaches 0.

这篇关于如何从UTC转换为本地时间用C?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆