linux 通过 /proc/[pid]/stat 的第22字段 starttime(系统启动后 ticks)结合 /proc/sys/kernel/btime 和 clk_tck 换算 unix 时间戳;macos 用 sysctl("kern.boottime") 与 kinfo_proc.p_starttime 相加;windows 用 getprocesstimes 的 filetime 减去 windows-unix epoch 差值转换。

Linux 下读取 /proc/[pid]/stat 获取启动时间(非 wall-clock)
Linux 内核不直接暴露进程的绝对启动时间戳,但提供了一个相对值:starttime 字段,单位是「系统启动后的 clock ticks」。它在 /proc/[pid]/stat 的第 22 个字段(从 1 开始计数),需结合系统启动时间(btime)换算成 Unix 时间戳。
常见错误是直接用 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) —— 那是 CPU 占用时间,不是启动时刻;也有人误读 /proc/[pid]/status 中的 CreateTime(该字段不存在于标准内核)。
- 先读取
/proc/sys/kernel/btime得到系统启动的 Unix 秒数(整数) - 再读
/proc/self/stat,按空格分割后取第 22 项(注意:字段含括号,需跳过前导括号并正确解析) - 用
sysconf(_SC_CLK_TCK)获取 tick 频率(通常是 100),算出进程启动距系统启动的秒数:starttime / (double)clk_tck - 最终 Unix 时间戳 =
btime + (starttime / clk_tck),结果为double或uint64_t秒级(若需毫秒级,保留小数部分乘 1000)
macOS 上必须用 sysctl + kinfo_proc
macOS 没有 /proc,得走 sysctl 接口查本进程的 kinfo_proc 结构体,其中 kp_proc.p_starttime.tv_sec 和 .tv_usec 组成 boot-time-relative 的启动时间。但注意:这个时间仍是相对于系统启动时刻,不是 Unix 时间戳。
关键点在于 macOS 不公开系统启动的绝对 Unix 时间(btime 不可用),只能通过 sysctl("kern.boottime") 查 struct timeval,它给出的是系统启动的 Unix 时间戳 —— 这正是你需要的基准。
- 调用
sysctl查询"kern.boottime",拿到struct timeval boottime - 再调用
sysctl查询"kern.proc.pid.[pid]"(或用sysctlbyname("kern.proc.pid.0")配合getpid())获取kinfo_proc - 将
kp_proc.p_starttime.tv_sec加到boottime.tv_sec,微秒部分相加后处理进位,得到完整 Unix 时间戳(struct timeval或uint64_t) - 别漏掉
#include <sys></sys>和<sys></sys>,否则编译报错sysctl: implicit declaration
Windows 用 GetProcessTimes 需手动转 UTC
GetProcessTimes 返回的是 FILETIME(100 纳秒精度,自 1601-01-01 起),不是 Unix 时间戳。直接减去 Unix epoch 偏移量即可转换,但必须注意:FILETIME 是本地时区无关的 UTC 值,无需调用 FileTimeToLocalFileTime。
常见坑是把 lpCreationTime 当作毫秒时间戳用,或错误使用 GetSystemTimeAsFileTime 对比 —— 那只是当前时间,和进程无关。
- 调用
GetProcessTimes(GetCurrentProcess(), &ftCreate, ..., ...),只关心ftCreate - 用
ULARGE_INTEGER把ftCreate转成 64 位整数(单位:100 纳秒) - Unix epoch(1970-01-01)距 Windows epoch(1601-01-01)为 11644473600 秒 =
116444736000000000ULL个 100 纳秒 - Unix 时间戳(微秒) =
(ft_as_uint64 - 116444736000000000ULL) / 10
跨平台封装要注意时钟源一致性
不同平台返回的时间精度和含义略有差异:Linux /proc 的 starttime 是调度器记录的 fork 时刻,可能比真正 exec 晚几毫秒;macOS 的 p_starttime 是内核创建进程结构体的时刻;Windows 的 CreationTime 是内核对象创建时间,最接近真实起点。
如果你在做性能监控或日志对齐,不要假设三者能精确对齐到毫秒级 —— 尤其在容器或虚拟化环境下,btime 可能被 cgroup 或 hypervisor 干扰。
建议封装时统一返回 std::chrono::system_clock::time_point,避免裸 time_t 或 uint64_t 引发时区/精度混淆;同时预留 fallback:当某平台失败(如 Linux 容器里 /proc 不可读),退回到 std::chrono::system_clock::now() 并打 warning 日志。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











