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

2024-04-18

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

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

在C中将包含本地时间的字符串转换为UTC https://stackoverflow.com/questions/1764710/converting-string-containing-localtime-into-utc-in-c

C/C++ 中本地时间和 GMT/UTC 之间的转换 https://stackoverflow.com/questions/761791/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);

Or

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

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

编辑 2013年11月29日:基于下面“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(因此 POSIX 规范time_t作为自纪元以来的秒数),我首先使用 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代表当地时间的纪元。将自纪元以来的秒数添加到tm_sec这个领域的struct tm,然后调用mktime将其规范化。

Edit:实际上唯一的 POSIX 依赖是有一个已知的纪元(time_t)0对应于.如果您确实需要的话,也许您可​​以找到解决方法......例如使用对两者的调用gmtime and localtime at time_t 0..

Edit 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 longoffset 和一个不断添加不大于增量的循环INT_MAX/2(或小于INT_MIN/2)并打电话mktime重新归一化,直到偏移量达到 0。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在C中将UTC时间转换为本地时间? 的相关文章

随机推荐

  • 有没有办法退出 Greasemonkey 脚本?

    我知道你可以使用return 从 Greasemonkey 脚本返回 但前提是您不在另一个函数中 例如 这是行不通的 Begin greasemonkey script function a return Only returns from
  • docker 镜像中的 openVPN

    我正在尝试创建一个 docker 映像 其中包含一个 python 脚本 该脚本使用 openVPN 通过 VPN 连接到 API 但是 我似乎无法让 openVPN 正常工作 我有我的 docker 文件 Install openVPN
  • 修改函数内的点 (...)

    我正在尝试修改自定义函数内的点 这是我的一个简化示例plot2函数 它在屏幕上显示一个绘图type p 默认 并保存 svgtype l 当其中之一出现时 问题就出现了 绘图选项已在函数中 在这个例子中 type 由多个实际参数匹配 plo
  • 如何防止 IntelliJ IDEA 在启动时重新分配文件类型关联?

    我正在使用 IntelliJ IDEA Ultimate 18 1 而 Jenkinsfile 支持很糟糕 值得庆幸的是 将文件视为 Groovy 是我可以接受的解决方法 这涉及到 删除 Jenkinsfile 关联 在Groovy组下添加
  • flex:如何防止在flex3文本输入中粘贴(ctrl+V)?

    你好 我需要禁用在文本输入中粘贴文本 flex 3 CTRL V 任何想法 reagrds 这只会阻止粘贴多个字母 但它确实适用于大多数用途
  • CSS悬停菜单:获取悬停菜单项以保持悬停状态CSS

    在这种情况下 我如何设置在抛出菜单项时保持悬停状态 是否有仅 CSS 的方法或者我必须引入一些 javascript 谢谢 It is只需CSS即可实现 例如 如果您的菜单由嵌套列表组成 li hover background color
  • 本机 C++ 中的 CreatePushNotificationChannelForApplicationAsync

    我正在尝试在本机 C 代码中使用 Windows 推送通知 但我在实施方面遇到了困难 我正在打电话CreatePushNotificationChannelForApplicationAsync但它返回HRESULT FROM WIN32
  • 对于 JavaScript 多维数组的深层复制,深一层似乎就足够了。这是真的吗?

    注意 我只是一个新手编码员 所以这个问题的核心可能存在明显的错误或误解 本质上 我需要将 JavaScript 中的多维数组 按值 深度复制到未知的深度 我认为这需要一些复杂的递归 但它seems在 JavaScript 中 您只需复制一层
  • JSP、JavaScript:将字节[]显示为图像

    我使用以下代码片段从文件中选择和读取图像 div class col md 6 form group div
  • 模拟绘画应用的笔触

    我正在尝试编写一个应用程序 可用于使用模拟笔触创建看起来像绘画的图片 是否有任何好的资源可以提供模拟笔触的简单方法 例如 给定用户拖动鼠标经过的鼠标位置列表 画笔宽度和画笔纹理 如何确定要在画布上绘制的内容 我尝试将画笔纹理倾斜到鼠标移动的
  • Eclipse 无法识别 Android 上的“R.id...”

    有什么想法为什么 Eclipse 有时会失败并且无法识别几秒钟前执行的代码吗 下面代码中的 R 下面有红色波浪线 而 5 分钟前还没有 而且我没有更改任何代码 这种情况在 Eclipse 中经常发生 通常我将其关闭并重新启动 一切顺利 这次
  • 在 ansible 角色中引用 defaults/main.yml 中的变量

    我的角色设置如下 角色 测试 任务 main yml name Generate people files template src test j2 dest tmp item name cfg loop people 角色 测试 模板 t
  • 使用 Servlet 和 JSP 验证数字

    我在学习 Web 开发的同时正在开发一个小型 Servlet 和 JSP 应用程序 我有一个关于 jsp 和 servlet 之间的验证和传递值的问题 我有一个 啤酒 类 具有 评级 属性 双精度类型 加载 edit jsp 的 servl
  • Codeigniter - 返回视图作为数据不起作用[重复]

    这个问题在这里已经有答案了 我在 CodeIgniter 2 0 2 中将视图作为数据返回时遇到问题 我不确定此版本的 CI 中是否提供此功能 这可能是问题所在 但我希望不是这样 因为目前无法选择升级 我们运行两个两个网站 其中一个我们使用
  • 如何只选择表格中的几列

    我有一个包含大约 1000 列的表 当我使用 Select from Table 它返回表的整个记录 但我只想要有限的记录列 col1 col2 col3 col4 col 5 col1000
  • boost::asio 将套接字转换为安全套接字

    我正在用 C 为 Minecraft 游戏编写一个服务器 客户端通过普通套接字向服务器发送初始握手数据包 然后 服务器将 RSA 密钥发送回游戏 并且从该点开始的所有套接字通信都将使用发送到客户端的 RSA 密钥进行 AES 加密 我有一个
  • 如何在 OpenShift 上安装 Nginx

    虽然我跟着https blog openshift com lightweight http serving using nginx on openshift https blog openshift com lightweight htt
  • 如何沿着简单的路径移动相机

    如何沿着简单的路径 由顶点 点数组创建 移动相机 我需要自动移动它 而不是像第一人称射击游戏那样通过键盘 鼠标事件来移动它 找了这个例子 http trijs org examples webgl geometry extrude spli
  • 如何“重写”现有的 vim 键绑定?

    I want to assign CTRL L to go the next tab tabnext I placed it at vimrc nmap
  • 如何在C中将UTC时间转换为本地时间?

    这是一个简单的问题 但解决方案似乎远非简单 我想知道如何从 UTC 转换为本地时间 我正在寻找一种标准的 C 解决方案 并且或多或少保证可以在任何位置的任何计算机上工作 我已仔细阅读以下链接 但在那里找不到解决方案 在C中将包含本地时间的字