<p>最可靠方法是用std::chrono::system_clock::now() - 24h,它基于单调时钟、规避时区/闰秒/溢出问题;转字符串时须显式指定localtime或gmtime以正确处理时区。</p>

用 std::chrono 减去 24 小时最可靠
直接用 std::chrono::system_clock::now() 获取当前时间点,再减去 24h(C++14 起支持字面量),结果是精确的 std::chrono::time_point。它不依赖时区、夏令时或日历计算,纯基于系统时钟滴答,避免了 tm 手动拆解导致的跨天/跨月错误。
常见错误是用 time_t 减 86400 秒:看似合理,但若系统时钟在期间被 NTP 调整过,或遇到闰秒(虽然 POSIX 通常忽略),结果可能偏移;更隐蔽的是某些嵌入式平台 time_t 是 32 位,2038 年后溢出风险也会传导到这种“硬减”逻辑里。
auto now = std::chrono::system_clock::now();-
auto yesterday = now - 24h;(需#include <chrono>,using namespace std::literals;) - 如需转为
time_t:用std::chrono::system_clock::to_time_t(yesterday)
转成可读字符串时注意时区
std::chrono::time_point 本身无时区信息,转字符串必须显式指定时区处理方式。直接用 std::ctime(&t) 会按本地时区解释,而 std::gmtime(&t) 按 UTC 解释——两者差值就是本地偏移,24 小时前的时间点在不同时区下对应不同日历日期。
例如北京时间(UTC+8)凌晨 1 点减 24 小时是前一天凌晨 1 点,但 UTC 时间是前一天 17:00;若误用 gmtime 再格式化,会显示成“昨天 17:00”,而非你预期的“昨天 01:00”。
立即学习“C++免费学习笔记(深入)”;
- 要本地时间字符串:先转
time_t,再用std::localtime+std::strftime - 要 UTC 字符串:用
std::gmtime+std::strftime - C++20 起可用
<format>和std::chrono::zoned_time更安全,但目前主流编译器支持仍有限
Windows 上 GetSystemTimeAsFileTime 不适合此场景
有人试图用 Win32 API 的 FILETIME(100 纳秒精度)手动减 24×60×60×10⁷,这在数学上没错,但 FILETIME 表示的是自 1601-01-01 UTC 起的计数,和 std::chrono::system_clock 的纪元(通常是 1970-01-01)不同,直接换算易出错;且 GetSystemTimeAsFileTime 不保证单调性(系统时间被修改时可能倒流),而 system_clock::now() 在现代标准库实现中已适配 Windows 的 QueryPerformanceCounter 或类似高精度单调时钟。
- 除非你在写内核驱动或必须绕过 C++ 标准库,否则别碰
FILETIME算术 - 跨平台代码一律优先走
std::chrono - 若需微秒级以下精度(如性能分析),才考虑
steady_clock,但它不能转为日历时间
测试时别用固定 time_t 值硬编码
写单元测试时,如果用类似 time_t test_now = 1717027200;(对应 2024-05-30 00:00:00 UTC)再减 86400,看似能复现“昨天”,但实际掩盖了时区转换逻辑缺陷——因为测试值本身没带时区上下文。一旦函数内部混用 localtime 和 gmtime,测试通过但线上出错。
- 测试应覆盖本地时区和 UTC 两种路径,用真实
system_clock::now()快照(哪怕只 run 一次) - mock 时钟需 mock 整个
system_clock特化,而非仅替换time()函数 - CI 环境时区可能为 UTC,本地开发机可能是 CST,这点差异必须出现在测试断言里
时区转换那步最容易被跳过——不是代码写不出来,而是开发者心里默认“就该是本地时间”,结果部署到服务器后所有定时任务提前或延后 8 小时。


















