How to convert a UTC date & time to a time_t in C++?
我想转换UTC日期& 以年,月,日等数字给出的时间到time_t。 有些系统为此目的提供
到目前为止我找到的唯一解决方案是使用setenv将本地时区设置为UTC,然后调用
我还看到了尝试使用
您认为什么是最佳解决方案?
我决定实现我自己的mkgmtime版本,它比我想象的要容易。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | const int SecondsPerMinute = 60; const int SecondsPerHour = 3600; const int SecondsPerDay = 86400; const int DaysOfMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; bool IsLeapYear(short year) { if (year % 4 != 0) return false; if (year % 100 != 0) return true; return (year % 400) == 0; } time_t mkgmtime(short year, short month, short day, short hour, short minute, short second) { time_t secs = 0; for (short y = 1970; y < year; ++y) secs += (IsLeapYear(y)? 366: 365) * SecondsPerDay; for (short m = 1; m < month; ++m) { secs += DaysOfMonth[m - 1] * SecondsPerDay; if (m == 2 && IsLeapYear(year)) secs += SecondsPerDay; } secs += (day - 1) * SecondsPerDay; secs += hour * SecondsPerHour; secs += minute * SecondsPerMinute; secs += second; return secs; } |
我主要担心的是
这个结果也意味着C库不会考虑闰秒,这本身就是一件坏事,但对我的目的有好处。这两个功能将长期保持一致。为了绝对确定,我使用此函数的Timestamp类总是快速检查程序启动并证明一些有意义的值的一致性。
为了完整性,这里是mkgmtime()的一个版本,它将struct tm *作为参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | static time_t mkgmtime(const struct tm *ptm) { time_t secs = 0; // tm_year is years since 1900 int year = ptm->tm_year + 1900; for (int y = 1970; y < year; ++y) { secs += (IsLeapYear(y)? 366: 365) * SecondsPerDay; } // tm_mon is month from 0..11 for (int m = 0; m < ptm->tm_mon; ++m) { secs += DaysOfMonth[m] * SecondsPerDay; if (m == 1 && IsLeapYear(year)) secs += SecondsPerDay; } secs += (ptm->tm_mday - 1) * SecondsPerDay; secs += ptm->tm_hour * SecondsPerHour; secs += ptm->tm_min * SecondsPerMinute; secs += ptm->tm_sec; return secs; } |
如上所述,虽然
在考虑之后,我想出了以下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | time_t mkgmtime(struct tm * pt) { time_t ret; /* GMT and local time */ struct tm * pgt, * plt; ret = mktime(pt); pgt = g_memdup(gmtime(ret), sizeof(struct tm)); plt = g_memdup(localtime(ret), sizeof(struct tm)); plt->tm_year -= pgt->tm_year - plt->tm_year; plt->tm_mon -= pgt->tm_mon - plt->tm_mon; plt->tm_mday -= pgt->tm_mday - plt->tm_mday; plt->tm_hour -= pgt->tm_hour - plt->tm_hour; plt->tm_min -= pgt->tm_min - plt->tm_min; plt->tm_sec -= pgt->tm_sec - plt->tm_sec; ret = mktime(plt); g_free(pgt); g_free(plt); return ret; } |
可以通过删除
这应该适用于所有公开
它确实存在一个潜在的错误:如果时区的UTC偏移因DST标志中未反映的原因而发生变化,则转换时间周围的时间戳可能会被错误地解释:标准情况是立法改变其时区(例如立陶宛从苏联时间独立后到CET,几年后去EET)。一些立法在夏季中期有两倍的DST,每年通过3种不同的UTC偏移进行循环,DST标志无法代表。