繁体   English   中英

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

[英]How safe is it to assume time_t is in seconds?

我正在做很多时间计算,通过添加秒来构建相对于其他时间对象的时间对象。 该代码应该在嵌入式设备和服务器上运行。 大多数文档都说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);
    }
}

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 您可以使用mktimelocaltimetime_tstruct 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_clockto_time_tfrom_time_tstd::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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM