Linux通过/proc/[pid]/stat第22字段(jiffies)结合/proc/stat的btime计算启动时间戳,Windows则用GetProcessTimes获取FILETIME后转为system_clock::time_point;两者均不可用steady_clock倒推。

Linux 下可以通过 /proc/[pid]/stat 读取进程启动时间(相对于系统启动时刻的 jiffies),再结合 /proc/uptime 和系统启动时间反推真实时间戳;Windows 则需用 GetProcessTimes 获取创建时间,再转为 std::chrono::system_clock::time_point。两者都不能直接拿 std::chrono::steady_clock 或当前时间“倒推”,因为进程可能被挂起、休眠或迁移。
Linux:从 /proc/self/stat 提取启动时间并转为 std::chrono::system_clock::time_point
关键字段是 /proc/[pid]/stat 的第 22 个字段(从 1 开始计数),表示进程启动后经过的 clock ticks(jiffies)。需要除以 sysconf(_SC_CLK_TCK) 得到秒数,再用系统启动时间(来自 /proc/stat 的 btime 行)相加。
-
/proc/stat中btime是内核启动时间(秒级 Unix 时间戳),不是 uptime -
/proc/self/stat第 22 字段是无符号 long,解析时需跳过括号包围的 comm 字段(第 2 字段),推荐用std::istringstream+ignore安全读取 - 不要用
uptime命令输出或/proc/uptime的第一个值做换算——那是系统运行时长,不是启动时间戳 - 示例片段:
#include <fstream>
#include <sstream>
#include <chrono>
#include <unistd.h>
#include <climits><p>auto get_process_start_time() -> std::chrono::system_clock::time_point {
std::ifstream stat{"/proc/self/stat"};
long start_ticks;
std::string dummy;
// 跳过 pid 和 comm(含括号)
stat >> dummy >> dummy;
for (int i = 0; i > dummy;
stat >> start_ticks;</p>
<pre class="brush:php;toolbar:false;">long clk_tck = sysconf(_SC_CLK_TCK);
std::ifstream btime_f{"/proc/stat"};
std::string line;
long btime = 0;
while (std::getline(btime_f, line)) {
if (line.substr(0, 6) == "btime ") {
btime = std::stol(line.substr(6));
break;
}
}
auto secs = std::chrono::seconds{btime + start_ticks / clk_tck};
return std::chrono::system_clock::time_point{secs};
}
Windows:用 GetProcessTimes 获取创建时间并转换为 std::chrono
GetProcessTimes 返回的 FILETIME 是 Windows 纪元(1601-01-01)以来的 100ns 单位整数,必须通过 FileTimeToSystemTime 或更稳妥地用 ULARGE_INTEGER 转成 100ns 自 1970-01-01 的偏移,再构造 std::chrono::system_clock::time_point。
- 直接对
FILETIME成员做 reinterpret_cast 会因大小端或结构填充出错,必须用ULARGE_INTEGER联合体安全读取 64 位值 - Windows 纪元到 Unix 纪元差 11644473600 秒(即 1164447360000000000 个 100ns),这个常量不能手算,应定义为 constexpr
- 注意
GetProcessTimes需要PROCESS_QUERY_INFORMATION权限,但当前进程默认有 - 示例片段:
#include <windows.h>
#include <chrono><p>constexpr uint64_t WINDOWS_EPOCH_TO_UNIX_EPOCH_100NS = 1164447360000000000ULL;</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/gongju/2823" title="C++14"><img
src="https://img.php.cn/upload/manual/001/431/639/6ac8b33c327c4749.png" alt="C++14" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="overflowclass">C++14</a>
<p class="overflowclass">C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。</p>
</div>
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<p>auto get_process_start_time() -> std::chrono::system_clock::time_point {
FILETIME ft_create, ft_exit, ft_kernel, ft_user;
if (!GetProcessTimes(GetCurrentProcess(), &ft_create, &ft_exit, &ft_kernel, &ft_user))
return {};</p>
<pre class="brush:php;toolbar:false;">ULARGE_INTEGER li;
li.LowPart = ft_create.dwLowDateTime;
li.HighPart = ft_create.dwHighDateTime;
auto unix_ns = std::chrono::nanoseconds{(li.QuadPart - WINDOWS_EPOCH_TO_UNIX_EPOCH_100NS) * 100};
return std::chrono::system_clock::time_point{
std::chrono::duration_cast<:chrono::system_clock::duration>(unix_ns)
};</:chrono::system_clock::duration>
}
跨平台封装注意事项与常见误判点
别试图用 std::chrono::steady_clock::now() 减去进程运行时长来估算启动时间——steady_clock 不保证和系统时钟对齐,且不反映挂起/休眠时间;也别依赖 getrusage 或 clock_gettime(CLOCK_PROCESS_CPUTIME_ID),它们返回的是 CPU 时间,不是墙上时间。
- Linux 下若
/proc不可用(如容器中无 procfs 挂载),该方法直接失效,需 fallback 到启动时记录时间戳 - Windows 上
FILETIME精度是 100ns,但实际创建时间精度受系统定时器分辨率限制(通常 10–15ms),不要假设能拿到微秒级准确值 - 两个平台返回的时间都可能早于系统时钟当前值(如系统时间被 NTP 向后跳变),但这是正常现象,不代表计算错误
- 没有标准 C++ 库函数能跨平台完成这件事,
只负责转换,源头数据必须走系统 API
最易被忽略的是:Linux 的 btime 在某些内核配置下可能不可靠(比如启用了 CONFIG_BOOTTIME_TRACING 但未导出),而 Windows 的 GetProcessTimes 在低权限沙箱中可能失败——这时候得提前准备好降级方案,比如启动时用 std::chrono::system_clock::now() 手动打点并全局保存。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










