C++20推荐用std::chrono+std::format:先构造std::chrono::seconds,再duration_cast拆解为时分秒,用{:02}补零;C++17及以下直接整除取余,配合std::ostringstream与setfill/setw格式化。
用
+
(C++20)最干净
如果你的编译器支持 C++20 且启用了
(如 MSVC 19.3x、GCC 13+ 配合
),这是目前最接近“优雅”的方案:类型安全、无手动除法、不依赖 C 风格函数。
常见错误是直接对原始整数秒调用
,结果只能输出数字本身,无法自动拆解为时分秒。必须先转成
,再借助
拆解。
用
构造持续时间对象
分别 cast 到
、
、
,注意后两者要减去高位部分
中用
补零,避免写
风格的格式串
兼容 C++11/14/17:老老实实做整除和取余
绝大多数项目仍卡在 C++17 或更低版本,
不可用,也别硬套
(它要塞进
结构体,得先转成日历时间,秒数超 86400 就溢出或错乱)。
直接算最稳:所有主流编译器对整数除法优化极好,性能毫无压力,逻辑也一目了然。
立即学习
“
C++免费学习笔记(深入)
”;
小时:
剩余秒数:
分钟:
秒:
补零统一用
,比手拼字符串或
更安全
别踩
+
的坑
网上很多示例用
再
,这在秒数小于 86400(一天)时看似能跑,但本质是误用:
表示的是自 epoch 起的秒数,不是“持续时间”。传入
实际对应 1970-01-01 01:01:05 UTC,时区一变就错
超过 86400 秒(比如 90000),
会解析成“1970-01-02 01:00:00”,小时变成 01 而非期望的 25
跨夏令时、闰秒、甚至某些嵌入式平台的
实现,会让结果不可预测
除非你真想把秒数解释为某个日历时刻,否则永远别碰这套组合。
输出到
还是
?看场景选流操作
如果只是临时调试打印,直接用
配合
和
最轻量;如果要拼进日志、返回给上层或做进一步处理,必须构造
。
容易忽略的一点:
和
是流状态,会影响后续所有输出。如果写成全局
,后面打个普通数字也可能被补零。
调试用:用
隔离状态,或每次用
单次生效
生产用:封装成函数,返回
,避免副作用泄漏
性能敏感场景(高频调用):预分配
手动写入,跳过流对象开销(但多数情况没必要)
时分秒拆解本身没玄机,真正容易翻车的是混淆“持续时间”和“日历时间”,以及忽略流操作符的状态污染。选对抽象层级,比追求某一行“炫技”代码重要得多。
std::chronostd::formatstd::format-std=c++20 -lstdc++fsstd::formatstd::chrono::secondsstd::chrono::duration_caststd::chrono::seconds{total_sec}std::chrono::hoursstd::chrono::minutesstd::chrono::secondsstd::format{:02}printfint total_sec = 3665;
auto dur = std::chrono::seconds{total_sec};
auto h = std::chrono::duration_cast(dur);
auto m = std::chrono::duration_cast(dur - h);
auto s = std::chrono::duration_cast(dur - h - m);
std::string result = std::format("{:02}:{:02}:{:02}", h.count(), m.count(), s.count());
// → "01:01:05"
std::formatstrftimetmtotal_sec / 3600total_sec % 3600remaining / 60remaining % 60std::setfill('0') + std::setw(2)sprintfint total_sec = 3665;
int h = total_sec / 3600;
int m = (total_sec % 3600) / 60;
int s = total_sec % 60;
std::ostringstream oss;
oss << std::setfill('0') << std::setw(2) << h << ':'
<< std::setfill('0') << std::setw(2) << m << ':'
<< std::setfill('0') << std::setw(2) << s;
std::string result = oss.str(); // → "01:01:05"
localtimestrftimelocaltime(&time_t{sec})strftimetime_t3665localtimetime_tstd::coutstd::stringstd::coutstd::setfillstd::setwstd::stringstd::setfillstd::setwstd::cout << std::setfill('0')std::ostringstreamstd::cout << std::setfill('0') << std::setw(2) << xstd::stringstd::array