time_t 本身不包含时分秒,需用 localtime_r() 或 gmtime_r() 转为 struct tm 后读取 tm_hour、tm_min、tm_sec 字段;注意判空、线程安全及闰秒(tm_sec 可为 60)。

time_t 本身不包含时分秒,必须转换成 struct tm
time_t 是一个算术类型(通常是 long 或 int),表示自 Unix 纪元(1970-01-01 00:00:00 UTC)以来的秒数,它不带时区、不带格式、也不直接可读。想拿到“几点几分几秒”,必须用 localtime() 或 gmtime() 把它转成 struct tm——这个结构体里才有 tm_hour、tm_min、tm_sec 字段。
常见错误是直接对 time_t 做模运算试图“手算”时分秒,这忽略闰秒、夏令时、时区偏移,结果大概率错。
-
localtime()返回本地时区时间(受TZ环境变量或系统设置影响) -
gmtime()返回 UTC 时间,结果稳定、无歧义,适合日志时间戳或跨时区同步场景 - 两个函数都返回
struct tm*,且内部使用静态缓冲区——不能多线程直接共用返回值,需立即复制或改用线程安全版本(如localtime_r()/gmtime_r())
正确提取时分秒的三步操作
典型流程:获取 time_t → 转为 struct tm → 读取字段。注意指针判空和线程安全。
time_t now = time(nullptr);
if (now == -1) {
// 处理 time() 失败(极少见,但可能)
}
struct tm t;
if (localtime_r(&now, &t) == nullptr) {
// 转换失败(比如 time_t 值非法)
}
int hour = t.tm_hour; // 0–23
int minute = t.tm_min; // 0–59
int second = t.tm_sec; // 0–60(含闰秒)
- 务必检查
localtime_r()/gmtime_r()返回值是否为nullptr,尤其在嵌入式或受限环境中 -
tm_sec可能为 60(闰秒发生时),虽罕见但标准允许,不要硬写0 断言 - Windows 下
localtime_s()是等价替代,参数顺序不同,别混用
为什么不用 asctime() 或 strftime()?
如果你只要时分秒数字(比如做倒计时、比对分钟粒度),调用 strftime() 或拼接字符串是多余开销;asctime() 更是直接返回固定格式字符串("Wed Jan 01 00:00:00 1970\n"),还得再解析——纯浪费 CPU 和内存。
立即学习“C++免费学习笔记(深入)”;
- 直接读
tm_hour等字段是零分配、零格式化、最轻量的方式 - 只有需要输出到界面、写日志文件、或按特定格式(如 "14:23:05")组装字符串时,才用
strftime() -
strftime()的格式符要注意:%H是 24 小时制,%I是 12 小时制;%S输出的是秒数(00–60),不是毫秒
跨平台兼容性与陷阱
Linux/macOS 默认支持 localtime_r();Windows 需用 localtime_s(),且头文件和参数顺序不同:
// Windows
errno_t err = localtime_s(&t, &now);
if (err != 0) { /* 错误处理 */ }
- 别依赖
localtime()的返回值在多线程中安全——它返回指向静态缓冲区的指针,多个线程调用会互相覆盖 - C++20 引入了
<chrono>和std::format,但若只需基础时分秒,没必要引入复杂模板;time_t → tm仍是最直白可靠的选择 - 某些精简 libc(如 musl 或裸机环境)可能不提供
_r版本,此时需加锁或自己实现简易转换逻辑
真正容易被忽略的是:tm_hour 是本地时间,而 time_t 本身是 UTC 秒数。如果你在 UTC 时区外运行程序,又没意识到 localtime() 自动做了时区转换,就可能把“服务器时间”和“用户看到的时间”搞混。


















