假设time_t以秒为单位是多么安全?

时间:2013-10-19 13:28:25

标签: c++ date time time-t

我经常做很多计算,通过添加秒来构建相对于其他时间对象的时间对象。该代码应该在嵌入式设备和服务器上运行。大多数文档都说time_t它是某种算术类型,通常存储自纪元以来的时间。假设time_t存储了几秒钟以来的某些时间,这是多么安全?如果我们可以假设,那么我们可以使用加法和减法而不是localtimemktimedifftime

到目前为止,我已经使用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);
    }
}

6 个答案:

答案 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_tstruct tmmktimelocaltime之间进行转换。

答案 3 :(得分:1)

如果C ++ 11可用,请使用std::chrono::system_clockto_time_tfrom_time_tstd::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。