可靠获取系统重启时间需查windows事件日志id 12或linux journalctl --list-boots;windows用evtquery(evtqueryreversedirection)查system日志中event[system[(eventid=12)]],解析timecreated为filetime再转system_clock::time_point;linux优先解析journalctl输出,fallback到/proc/uptime粗算。

Windows上用GetTickCount64不够,得查事件日志
单纯调用GetTickCount64只能拿到系统已运行时长,不是重启时间。真正可靠的来源是 Windows 事件日志里的系统启动事件(ID 12 或 1074),对应System日志中Event ID 12(内核启动完成)或Event ID 1074(用户发起关机/重启)。需要使用 Windows API 的EvtQuery和EvtNext系列函数。
用EvtQuery查最近一次 Event ID 12 的时间
关键步骤是构造 XPath 查询表达式,按时间倒序取第一条匹配记录:
- 查询字符串必须用
Event[System[(EventID=12)]],注意括号嵌套和大小写 - 必须指定
EvtQueryReverseDirection标志,否则默认从最早开始遍历 -
EvtFormatMessage对EventRecordId或TimeCreated字段格式化时,需传入EvtFormatMessageTime并确保缓冲区足够(至少 32 字节) - 返回的
FILETIME需用FileTimeToSystemTime转为可读结构,别直接当成秒数处理
// 示例片段:获取最近一次 Event ID 12 的 TimeCreated
DWORD status = EvtQuery(NULL, L"System", L"*[System[(EventID=12)]]",
EvtQueryReverseDirection | EvtQueryTolerateQueryErrors, NULL);
// 后续用 EvtNext 获取首条事件,再用 EvtRender 提取 TimeCreated 字段
Linux下读/proc/sys/kernel/random/boot_id不行,得看uptime或journalctl
/proc/sys/kernel/random/boot_id每次启动生成新 UUID,但不带时间戳;真正可用的是:
-
cat /proc/uptime返回秒数,用time(NULL) - uptime_sec粗略算出启动时间(注意时区和系统时间是否准确) - 更可靠的是
journalctl --list-boots输出的 boot ID 列表,最后一行第一列是 boot index,第二列是启动时间(ISO 格式),可用system()+popen()捕获输出 - 若系统没启用 journald(如某些嵌入式或 minimal 安装),
/proc/uptime是唯一选项,但无法区分休眠唤醒和真正重启
跨平台封装要注意时区和权限问题
Windows 查询事件日志需要管理员权限(否则EvtQuery返回ERROR_ACCESS_DENIED);Linux 上journalctl --list-boots普通用户可执行,但journalctl -b -1查前一次启动可能受限于日志保留策略。
统一返回std::chrono::system_clock::time_point时,务必确认:FILETIME转time_t要减去 11644473600LL 秒(Windows 时间纪元偏移);Linux 用strtoll()解析journalctl输出的时间字符串时,得跳过带时区的+0800部分,或用strptime配合%Y-%m-%d %H:%M:%S格式。
实际部署时,别指望一次调用就覆盖所有边缘情况——比如 Windows 系统日志被清空、Linux journal 被轮转、或者容器环境里/proc/uptime反映的是宿主而非容器启动时间。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











