推荐使用 GetTickCount64 获取开机时间,它返回系统启动以来的毫秒数,无溢出风险,轻量可靠;需从 kernel32.dll 导入,配合 DateTime.UtcNow 推算 UTC 开机时刻。

用 GetTickCount64 获取开机时间(推荐)
Windows 系统本身不直接暴露“开机时间点”,但提供自系统启动以来的毫秒计数,GetTickCount64 是最轻量、最可靠的方式。它返回的是 64 位无符号整数,避免了旧版 GetTickCount 的 49.7 天溢出问题。
实操建议:
- 必须从
kernel32.dll导入,且调用前确认运行在 Windows 平台(.NET 5+ 可用OperatingSystem.IsWindows()判断) - 返回值是毫秒数,转为
DateTime需配合DateTime.UtcNow或DateTime.Now推算:当前时间减去该毫秒数 → 开机时刻 - 注意时区:用
DateTime.Now推算会受本地时区影响;若需 UTC 开机时间,统一用DateTime.UtcNow
[DllImport("kernel32.dll")]
public static extern long GetTickCount64();
<p>var uptimeMs = GetTickCount64();
var bootTime = DateTime.UtcNow - TimeSpan.FromMilliseconds(uptimeMs);为什么不用 ManagementObjectSearcher 查 Win32_OperatingSystem
虽然 WMI 能读到 LastBootUpTime 字段,但它本质是字符串(如 "20240512102345.000000+480"),解析麻烦、性能差、权限要求高,且在某些精简版系统或容器中可能不可用。
常见错误现象:
- 抛出
UnauthorizedAccessException:WMI 默认需要管理员权限或特定 DCOM 配置 - 查询超时或卡住:WMI 服务响应慢,尤其在远程或资源紧张机器上
-
LastBootUpTime为空或格式异常:部分系统(如某些 IoT 版本)未正确填充该字段
除非你已在项目中重度依赖 WMI 且需要其他系统信息,否则没必要为开机时间单独引入这套链路。
PerformanceCounter 的 System Up Time 计数器能用吗
可以,但不推荐。它底层其实也调用 GetTickCount64,只是多了一层 .NET 封装和性能计数器初始化开销。
使用场景有限:
- 仅适用于 Windows Desktop/.NET Framework(.NET Core 3.0+ 已移除对部分性能计数器的支持)
- 首次创建
PerformanceCounter实例时有明显延迟(约几十毫秒),不适合高频调用 - 计数器名称、类别名大小写敏感,且不同 Windows 版本略有差异,比如英文系统是
"System",中文系统可能是"系统"
示例中容易漏掉 ReadOnly 检查和异常兜底:
try {
using var pc = new PerformanceCounter("System", "System Up Time");
pc.NextValue(); // 必须先调一次
var uptimeSec = pc.NextValue();
} catch (InvalidOperationException) { /* 计数器不存在或权限不足 */ }跨平台兼容性怎么处理
.NET 6+ 项目若需支持 Linux/macOS,GetTickCount64 会直接报 DllNotFoundException。此时不能硬切 WMI(Linux 上根本没这玩意),得按平台分路径。
实操要点:
- Linux 下可用
/proc/uptime读取系统运行秒数(需File.ReadAllText("/proc/uptime")后取空格前数字) - macOS 可用
sysctl kern.boottime命令,解析输出中的sec = xxx - 别自己拼接 shell 命令——用
Process.Start开销大、易出错;优先查Environment.OSVersion+ 条件编译,或封装成小工具类
最容易被忽略的一点:虚拟机里 /proc/uptime 反映的是宿主机还是客户机?答案是客户机——但某些嵌套虚拟化或容器环境(如 WSL2)中,这个值可能和宿主机同步,导致误判。真要精确,得结合 dmidecode 或 systemd 日志,那就超出“获取开机时间”本身的需求了。










