[英]How safe is it to assume time_t is in seconds?
我正在做很多时间计算,通过添加秒来构建相对于其他时间对象的时间对象。 该代码应该在嵌入式设备和服务器上运行。 大多数文档都说time_t
是某种算术类型,通常存储自纪元以来的时间。 假设time_t
从某事起存储秒数有多安全? 如果我们可以假设,那么我们可以只使用加法和减法而不是localtime
、 mktime
和difftime
。
到目前为止,我已经通过使用constexpr bool time_tUsesSeconds
解决了这个问题,表示假设time_t
使用秒是否安全。 如果假设time_t
以秒为单位是不可移植的,有没有办法自动初始化该常量?
time_t timeByAddingSeconds(time_t theTime, int timeIntervalSeconds) {
if (Time_tUsesSeconds){
return theTime + timeIntervalSeconds;
} else {
tm timeComponents = *localtime(&theTime);
timeComponents.tm_sec += timeIntervalSeconds;
return mktime(&timeComponents);
}
}
POSIX 规范规定了它以秒为单位的事实,因此,如果您正在为符合 POSIX 的环境编码,则可以依靠它。
C++ 标准还规定time_t
必须是算术类型。
无论如何,Unix 计时系统(自 Epoch 以来的第二个)将在 2038 年溢出。因此,很可能在此日期之前,C++ 实现将切换到其他非 int 数据类型(64 位 int 或 a更复杂的数据类型)。 无论如何,切换到 64 位 int 会破坏与以前代码的二进制兼容性(因为它需要更大的变量),并且应该重新编译所有内容。 使用 32 位不透明句柄不会破坏二进制兼容性,您可以更改底层库,并且一切仍然有效,但是time_t
不再是以秒为单位的时间,它将是以秒为单位的时间数组的索引。 出于这个原因,建议您使用您提到的函数来操作time_t
值,并且不要对time_t
做任何假设。
标准 C 或标准 C++ 中对time_t
表示的单位没有要求。 要便携地使用秒,您需要使用struct tm
。 您可以使用mktime
和localtime
在time_t
和struct tm
之间进行转换。
由于time_t
是一种算术类型,而不是确定time_t
是否以秒为单位,您可以改为计算代表一秒的time_t
值,然后使用它。 我之前写的这个答案解释了该方法并有一些注意事项,这里有一些示例代码( bad_time()
是一个自定义异常类,这里):
time_t get_sec_diff() {
std::tm datum_day;
datum_day.tm_sec = 0;
datum_day.tm_min = 0;
datum_day.tm_hour = 12;
datum_day.tm_mday = 2;
datum_day.tm_mon = 0;
datum_day.tm_year = 30;
datum_day.tm_isdst = -1;
const time_t datum_time = mktime(&datum_day);
if ( datum_time == -1 ) {
throw bad_time();
}
datum_day.tm_sec += 1;
const time_t next_sec_time = mktime(&datum_day);
if ( next_sec_time == -1 ) {
throw bad_time();
}
return (next_sec_time - datum_time);
}
您可以调用该函数一次并将值存储在一个常量中,然后在需要time_t
秒时使用它。 我不认为它会在constexpr
工作。
如果 C++11 可用,您可以使用std::chrono::system_clock
to_time_t
std::chrono::system_clock
的to_time_t
和from_time_t
与std::chrono::time_point
from_time_t
相互转换,并使用std::chrono::time_point
的算术运算符。
如果您的计算涉及公历,您可以使用HowardHinnant/date库,或 C++20 的chrono新日历工具(它们具有基本相同的 API )。
我的两分钱:在 Windows 上,随着时间的推移以秒为单位,但一秒增加到下一秒所需的时间通常为 18*54.925 毫秒,有时为 19*54.925。 原因在这篇文章中有解释。
(回答自己的问题)
一个答案表明,只要使用 posix, time_t
就以秒为单位,并且time_t
算术应该可以工作。
第二个答案计算每秒的 time_t,并在进行算术时将其用作因子。 但是仍然有一些关于time_t
假设。
最后我决定可移植性更重要,我不希望我的代码在某些嵌入式设备上默默地失败。 所以我使用了第三种方式。 它涉及存储一个整数,表示自程序启动以来的时间。 即我定义
const static time_t time0 = time(nullptr);
static tm time0Components = *localtime(&time0);
整个程序中使用的所有时间值都只是整数,表示自time0
以来的时间差(以秒为time0
。 为了从time_t
到这个增量秒,我使用difftime
。 回到time_t
,我使用这样的东西:
time_t getTime_t(int timeDeltaSeconds) {
tm components = time0Components;
components.tm_sec += timeDeltaSeconds;
return mktime(&components);
}
这种方法允许像+
, -
这样的操作便宜,但回到time_t
是昂贵的。 请注意,时间增量值仅对程序的当前运行有意义。 另请注意,当时区发生变化时,必须更新 time0Components。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.