我经常做很多计算,通过添加秒来构建相对于其他时间对象的时间对象。该代码应该在嵌入式设备和服务器上运行。大多数文档都说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);
}
}
答案 0 :(得分:9)
POSIX specification表示它是以秒为单位的事实,因此,如果您正在编写符合POSIX标准的环境,那么您可以依赖它。
C ++标准还规定time_t
必须是算术类型。
无论如何,unix计时系统(自Epoch以来的第二个)将在2038年溢出。因此,很可能在此日期之前,C ++实现将切换到其他非int数据类型(64b int或a更复杂的数据类型)。无论如何,切换到64b int将破坏与先前代码的二进制兼容性(因为它需要更大的变量),并且应该重新编译所有内容。使用32b opaque句柄不会破坏二进制兼容性,你可以更改底层库,一切仍然有效,但time_t
不再是几秒钟的时间,它是一个数组的索引,以秒为单位。出于这个原因,建议您使用您提到的函数来操作time_t值,而不要在time_t
上假设任何内容。
答案 1 :(得分:2)
而不是确定time_t
是否在几秒钟内,因为time_t
是算术类型,您可以改为计算代表一秒的time_t
值,并使用它。 This answer I wrote before解释了该方法并有一些注意事项,这里有一些示例代码(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);
}
您可以调用该函数一次并将值存储在const中,然后在需要time_t
秒时使用它。我不认为它会在constexpr
中起作用。
答案 2 :(得分:1)
time_t
表示的单位在标准C或标准C ++中没有要求。要以便携式移动数秒,您需要使用struct tm
。您可以使用time_t
和struct tm
在mktime
和localtime
之间进行转换。
答案 3 :(得分:1)
如果C ++ 11可用,请使用std::chrono::system_clock
的to_time_t
和from_time_t
与std::chrono::time_point
进行相互转换,并使用chrono的算术运算符。
如果您的计算涉及公历,则可以使用HowardHinnant/date库或chrono中C ++ 20的新日历功能(它们具有essentially the same API)。
答案 4 :(得分:0)
我的两分钱:在Windows上,它在几秒钟内随着时间的推移,但是一秒钟增加到下一秒的时间通常是18 * 54.925毫秒,有时是19 * 54.925。其原因在this post中解释。
答案 5 :(得分:0)
(回答自己的问题)
一个答案表明只要一个人使用posix,time_t
就会在几秒钟内完成,time_t
上的算术就可以了。
第二个答案计算每秒的time_t,并在进行算术时将其用作因子。但是仍然有一些关于time_t
的假设。
最后我决定可移植性更重要,我不希望我的代码在某些嵌入式设备上静默失败。所以我用第三种方式。它涉及存储一个表示程序启动后的时间的整数。即我定义了
const static time_t time0 = time(nullptr);
static tm time0Components = *localtime(&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。