将纪元时间转换为人类日期时间字符串,无需夏令时转换

Posted

技术标签:

【中文标题】将纪元时间转换为人类日期时间字符串,无需夏令时转换【英文标题】:Convert epoch time to human date time string without daylight saving conversion 【发布时间】:2015-03-06 19:12:50 【问题描述】:

我是 C 的新手,我目前正在做一个项目,我需要将纪元时间转换为人类日期和时间字符串。

我的 UTC 时间戳1411210794,用于 20th September 2014 10:59:54

然后我在 UTC 时间戳上运行以下函数以转换为人类可读的时间戳:

void UTCoTimeDate(char** date, char** time, long UTC, BOOL includeSeconds)

     time_t epch = UTC;
     struct tm *timeptr =  gmtime(&epch);
     asprintf(date, "%d-%.2d-%.2d", 1900 + timeptr->tm_year, timeptr->tm_mon+1, timeptr->tm_mday);
     if (includeSeconds)
     
        asprintf(time, "%.2d:%.2d:%.2d", timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec);
     
     else
     
        asprintf(time, "%.2d:%.2d", timeptr->tm_hour, timeptr->tm_min); 
     

当我通过 gdb 运行它并查看 tm *timeptr 内容时,小时已变为 11 而不是停留在 10。以下是 tm 结构的完整内容

tm_sec = 54, tm_min = 59, tm_hour = 11, tm_mday = 20, tm_mon = 8, tm_year = 114, tm_wday = 6, tm_yday = 262, tm_isdst = 1, tm_gmtoff = 3600,
  tm_zone = 0x806c488 "BST"

我原以为人类日期会在 10:59:54 而不是 11:59:54 回来。

【问题讨论】:

如果您修改代码以在调用gmtime() 之前打印UTC 和之后打印timeptr->tm_hour 并且UTC 的值为1411210794 并且小时值为11,那么您的gmtime()被打破。你实际上在哪个时区? (是 UTC±1,还是与 UTC 有更大的偏移?)有人添加了#define gmtime(x) localtime(x) 是否有任何风险?如果添加#undef gmtime,结果会改变吗? 【参考方案1】:

这是一个演示程序 (ttt.c):

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

static void dump_tm(const char *tag, const struct tm *tm)

    printf("%s: tm_sec = %.2d, tm_min = %.2d, tm_hour = %.2d, tm_mday = %.2d,"
           " tm_mon = %.2d, tm_year = %.3d, tm_wday = %d, tm_yday = %.3d,"
           " tm_isdst = %d, tm_gmtoff = %.5ld, tm_zone = \"%s\"\n",
           tag, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon,
           tm->tm_year, tm->tm_wday, tm->tm_yday, tm->tm_isdst, tm->tm_gmtoff,
           tm->tm_zone);


int main(void)

    time_t  t0 = 1411210794;
    struct tm *ut = gmtime(&t0);
    struct tm *lt = localtime(&t0);

    dump_tm("UTC", ut);
    dump_tm("Local", lt);
    return 0;

这是我 Mac 上的输出(Mac OS X 10.10.1、GCC 4.9.1 — 为 SO 添加了额外的换行符):

$ ./ttt
UTC: tm_sec = 54, tm_min = 59, tm_hour = 10, tm_mday = 20, tm_mon = 08, tm_year = 114,
tm_wday = 6, tm_yday = 262, tm_isdst = 0, tm_gmtoff = 00000, tm_zone = "UTC"
Local: tm_sec = 54, tm_min = 59, tm_hour = 03, tm_mday = 20, tm_mon = 08, tm_year = 114,
tm_wday = 6, tm_yday = 262, tm_isdst = 1, tm_gmtoff = -25200, tm_zone = "PDT"
$ TZ="Europe/London" ./ttt
UTC: tm_sec = 54, tm_min = 59, tm_hour = 10, tm_mday = 20, tm_mon = 08, tm_year = 114,
tm_wday = 6, tm_yday = 262, tm_isdst = 0, tm_gmtoff = 00000, tm_zone = "UTC"
Local: tm_sec = 54, tm_min = 59, tm_hour = 11, tm_mday = 20, tm_mon = 08, tm_year = 114,
tm_wday = 6, tm_yday = 262, tm_isdst = 1, tm_gmtoff = 03600, tm_zone = "BST"
$

机器的默认时区设置实际上是 America/Los_Angeles(尽管 TZ 环境变量在第一次调用中正式取消设置)。可以看到,UTC 值是一致的,但是本地时间值有本地时区缩写。

在没有相反信息的情况下,我不得不得出结论,尽管您有其他想法,但您实际上是在调用 localtime() 而不是 gmtime()。您可以尝试通过在函数调用前添加#undef gmtime 来确保调用gmtime() 函数。如果gmtime() 函数仍然产生错误的时间信息,那么您机器上的gmtime() 已损坏。但是,这似乎不太可能。

【讨论】:

感谢您的工作。我真的不明白为什么。当我搜索整个项目时,我唯一找到的是我正在调用的 gmtime,以及#undef 的 gmtime,我没有找到任何其他可能使 gmtime 以不同方式工作的东西 无法访问您的所有代码,我也不能说。我能做的最好的事情是 (a) 证明 gmtime() 应该完成这项工作,并且 (b) 您显示的分解时间(可能)不是 gmtime() 的输出,而是 localtime() 的输出,不知何故。 '很遗憾你使用asprintf() 来进行strftime() 所做的格式化。我很想使用char buffer[32];strftime(buffer, sizeof(buffer), "%Y-%m-%d", timeptr);,然后*date = strdup(buffer); 将输出复制到函数参数中。不过,这不一定像 asprintf() 那样快。 好的,谢谢您的帮助。至少它的工作原理,我已经用这个把头撞在墙上有一段时间了。我会做更多的挖掘,看看我能找到什么

以上是关于将纪元时间转换为人类日期时间字符串,无需夏令时转换的主要内容,如果未能解决你的问题,请参考以下文章

将纪元转换为人类可读的日期在 python 中不起作用

在 Mac OSX 上将 unix 纪元时间转换为人类可读的日期 - BSD

如何将纳秒的纪元时间转换为人类可读的?

使用 Java 将 unix 纪元转换为人类可读时的日期不正确

在mysql中将纪元数转换为人类可读的日期

如何在 Teradata 中将纪元时间转换为人类可读