14

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

到目前为止,我已经通过使用 a 解决了这个问题,表示假设使用秒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);
    }
}
4

6 回答 6

16

POSIX 规范说明了它以秒为单位的事实,因此,如果您正在为符合 POSIX 的环境进行编码,则可以依赖它。

C++ 标准还规定time_t必须是算术类型。

无论如何,Unix 计时系统(自 Epoch 以来的第二个)将在 2038 年溢出。因此,在此日期之前,C++ 实现很可能会切换到其他非 int 数据类型(64 位 int 或更复杂的数据类型)。无论如何,切换到 64 位 int 会破坏与以前代码的二进制兼容性(因为它需要更大的变量),并且应该重新编译所有内容。使用 32 位不透明句柄不会破坏二进制兼容性,您可以更改底层库,一切仍然有效,但time_t不再以秒为单位,它将成为以秒为单位的时间数组的索引。出于这个原因,建议您使用您提到的函数来操作time_t值,并且不要在time_t.

于 2013-10-19T13:42:06.203 回答
3

如果 C++11 可用,您可以使用std::chrono::system_clock'sto_time_tfrom_time_t转换为/从std::chrono::time_point,并使用 chrono 的算术运算符。

如果您的计算涉及公历,您可以使用HowardHinnant/date库,或 C++20 的新日历工具 chrono(它们具有基本相同的 API)。

于 2020-04-15T19:23:43.247 回答
2

不是确定是否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);
}

您可以调用该函数一次并将值存储在 const 中,然后在需要时使用它time_t。我不认为它会在一段时间内起作用constexpr

于 2013-10-19T15:14:24.177 回答
2

标准 C 或标准 C++ 中对表示的单位没有要求time_t。要以便携式方式使用秒,您需要使用struct tm. 您可以在time_t和之间转换struct tm和。mktimelocaltime

于 2013-10-19T13:36:17.573 回答
0

我的两分钱:在 Windows 上,它随着时间的推移以秒为单位但一秒增加到下一秒所需的时间通常是 18*54.925 毫秒,有时是 19*54.925。原因在这篇文章中进行了解释。

于 2013-10-19T13:53:15.440 回答
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。

于 2013-10-24T13:19:00.217 回答