【发布时间】:2016-07-11 02:15:13
【问题描述】:
在 libc 中有两个函数可以将系统时间转换为日历时间 - gmtime 和 localtime,但只有 localtime 具有反函数 - mktime。为什么gmtime没有反函数,如果不应该有,为什么gmtime存在?
【问题讨论】:
在 libc 中有两个函数可以将系统时间转换为日历时间 - gmtime 和 localtime,但只有 localtime 具有反函数 - mktime。为什么gmtime没有反函数,如果不应该有,为什么gmtime存在?
【问题讨论】:
我发现这段代码的工作令人满意:
namespace std {
time_t timegm(tm* _Tm)
{
auto t = mktime(_Tm);
return t + (mktime(localtime(&t)) - mktime(gmtime(&t)));
}
}
通过测试:
auto t1 = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
auto t2 = std::timegm(std::gmtime(&t1));
EXPECT_EQ(t1, t2);
【讨论】:
mktime(localtime(&t)) 和mktime(gmtime(&t)) 跨越夏令时变化怎么办?
要解释gmtime()的存在,需要一些上下文:
gmtime() 会将 时间戳 表示(自 1970-01-01 00:00:00 以来的秒数)转换为 分解时间表示(又名,struct tm),假设timestamp 时区是 UTC:
gmtime()函数将日历时间 timep 转换为 分解的时间表示,用Coordinated Universal 表示 时间 (UTC)。当年份不适合 整数。返回值指向一个静态分配的结构 这可能会被后续调用任何日期覆盖 和时间函数。
另一方面,localtime() 考虑了 [本地] 系统时区(包括夏令时):
localtime()函数将日历时间 timep 转换为 分解时间表示,相对于用户的时间表示 指定的时区。该函数的行为就像它调用了tzset(3)和 使用有关的信息设置外部变量 tzname 当前时区、时区与Coordinated之间的区别 世界时 (UTC) 和当地标准时间(以秒为单位),以及 如果适用夏令时规则,则将日光设置为非零值 在一年中的某些时候。
请注意,从1970-01-01 00:00:00 开始的秒数因时区而异(当1970-01-01 00:00:00 在纽约时,它显然不在例如东京)。
mktime() 基于 [local] 系统时区将 struct tm 转换为 time_t 值(自 1970-01-01 00:00:00 以来的秒数),不应解释为inverse 任何特定函数(例如localtime() 或gmtime()),因为inverse 术语可能[错误地] 解释为安全的跨系统转换:
mktime()函数转换分解的时间结构, 表示为当地时间,以日历时间表示。这 函数忽略调用者在 tm_wday 中提供的值 和 tm_yday 字段。 tm_isdst 字段中指定的值通知 mktime() 夏令时 (DST) 是否有效 对于 tm 结构中提供的时间:正值表示 DST 已生效;
还有一个名为 timegm() 的不可移植函数(用于 GNU 和 BSD 系统),它假定为 UTC 时区,例如 gmtime()。
参考文献
从 Linux 手册页项目 3.74 版的部分内容中检索到块引用的文本。
【讨论】:
mktime(),但是你需要在返回值中加上或减去UTC偏移量。
localtime 代替 gmtime 以同样的方式。那为什么gmtime 存在呢?
timegm()的非便携式扩展(仅在 GNU 和 BSD 系统上)
mktime 是否完全等同于 timelocal? timegm 会忽略本地时区吗?