最可靠方法是用difftime(t2,t1)获取秒差再除以3600,因time_t相减未定义且易溢出;应使用std::trunc处理浮点结果以获得整小时数。

直接用 difftime 得到秒数再除以 3600 最可靠
两个 time_t 相减本身没有定义行为(可能溢出、符号未指定),不能直接用 t2 - t1。标准且跨平台的做法是调用 difftime(t2, t1),它返回 double 类型的秒差,精度足够表示大多数实际时间跨度。
换算成小时时注意:向下取整、四舍五入、还是截断?多数场景要的是“完整经过的小时数”,即向零截断(trunc)或向下取整(floor),而非简单 (int)(diff_sec / 3600)——因为负数时 C++ 的整数除法是向零截断,而 difftime 可能返回负值(t2 )。
- 若确保
t2 >= t1,可用(long)(difftime(t2, t1) / 3600) - 若不确定顺序,推荐
static_cast<long>(std::trunc(difftime(t2, t1) / 3600))</long>(需#include <cmath>) - 避免
round(),除非你明确需要四舍五入(比如统计平均耗时)
time_t 差值不等于整数减法,尤其在 Windows 上
Windows 的 time_t 是 64 位有符号整数,但其底层实现和 POSIX 不完全一致;某些旧编译器(如 MSVC 低版本)甚至把 time_t 定义为 32 位。直接相减不仅语义非法,还可能因符号扩展或溢出导致错误结果,比如两个相隔多年的 time_t 值相减得到负数。
- 永远不要写
(t2 - t1) / 3600 - 不要假设
time_t是整数类型——C 标准只规定它是算术类型,具体实现可变 - 即使本地测试通过,换平台或换 libc 版本就可能崩
处理边界情况:跨夏令时、闰秒不影响 difftime
difftime 计算的是日历时间(calendar time)的绝对秒差,已经自动处理了时区切换、夏令时调整、甚至历史闰秒(只要系统时钟和 tzdata 正确)。你不需要手动解析 struct tm 或调用 mktime。
立即学习“C++免费学习笔记(深入)”;
- 错误做法:转成
tm后手动算年月日时分秒差——逻辑复杂、易错、且不处理 DST 跳变 - 正确做法:保持
time_t原始值,只走difftime - 唯一要注意的是:确保两个
time_t来自同一时区上下文(比如都来自time(nullptr),或都来自mktime的本地时间);混用 UTC 和本地时间会导致结果偏差整小时
示例:安全获取两时刻间整小时差
#include <ctime>
#include <cmath>
<p>long hours_between(time_t t1, time_t t2) {
double diff_sec = difftime(t2, t1);
return static_cast<long>(std::trunc(diff_sec / 3600.0));
}</p><p>// 使用:
time_t start = time(nullptr);
std::this_thread::sleep_for(3600s + 123s);
time_t end = time(nullptr);
long h = hours_between(start, end); // 得到 1,不是 1.034...</p>这里用 std::trunc 而非 static_cast<long></long> 直接强转,是因为后者对负浮点数的行为依赖实现(C++11 起明确定义为向零截断,但仍建议显式表达意图)。如果项目不允许 <cmath>,可用条件判断:diff_sec >= 0 ? static_cast<long>(diff_sec / 3600.0) : -static_cast<long>(-diff_sec / 3600.0)</long></long>。
最常被忽略的一点:difftime 返回 double,不是 long long;当时间跨度超过约 2.9e12 秒(约 9e10 小时,远超 Unix 时间范围),double 会丢失精度——不过这种场景现实中几乎不会遇到。


















