C#中如何基于系统空闲时间计算用户活动时长百分比
问题根因
现有代码存在两个核心错误,无法完成目标统计逻辑:
- 对
TimeSpan结构字段理解偏差:IdleTime.Seconds是空闲时长扣除整分钟后剩余的秒数(取值范围0-59),IdleTime.Minutes是扣除整小时后剩余的分钟数(取值范围0-59),二者做大小比较无实际业务意义。 - 缺少时间片切分、空闲时长累计核心逻辑,未处理连续空闲场景的重复计数问题:如果直接累加每秒读取的
IdleTime.Seconds,连续空闲120秒时会得到0+1+2+...+119的错误累计值,远大于实际空闲时长。
实现逻辑
要完成按时间片统计、计算活动占比的需求,按以下逻辑实现即可:
- 定义固定配置:单时间片长度、总统计时间片数量
- 以1秒为间隔采样,每一秒判断当前是否处于空闲状态(空闲时长大于等于1秒即判定当前秒为空闲),累计当前时间片的空闲秒数
- 到达单个时间片边界时,将当前片的空闲秒数累加到总空闲计数变量
Count中,重置当前片计数,开启下一个时间片统计 - 所有时间片统计完成后,按对应公式计算活动占比
可直接运行的修正代码
using System; using System.Runtime.InteropServices; using System.Threading; namespace MyMonitor { class Program { static void Main() { // 统计配置 const int timeSliceLength = 60; // 单个时间片长度:60秒 const int totalSlices = 2; // 总统计时间片数:2个,合计120秒 long Count = 0; // 存储累计总空闲秒数的变量 DateTime currentSliceStart = DateTime.Now; int currentSliceIdle = 0; int finishedSlices = 0; while (finishedSlices < totalSlices) { TimeSpan idle = IdleTime; Console.WriteLine($"Last Input: {LastInput.ToShortTimeString()}"); Console.WriteLine($"Idle for: {idle.TotalSeconds} Seconds"); // 当前秒判定为空闲:空闲时长>=1秒,说明这1秒内无用户输入 if (idle.TotalSeconds >= 1) { currentSliceIdle++; } // 判断是否到达当前时间片边界 double elapsedInSlice = (DateTime.Now - currentSliceStart).TotalSeconds; if (elapsedInSlice >= timeSliceLength) { Count += currentSliceIdle; Console.WriteLine($"当前时间片统计完成,本片空闲时长:{currentSliceIdle}秒"); // 重置状态开启下一片 finishedSlices++; currentSliceStart = DateTime.Now; currentSliceIdle = 0; } Thread.Sleep(TimeSpan.FromSeconds(1)); } // 计算结果 int totalDuration = timeSliceLength * totalSlices; long totalActiveSeconds = totalDuration - Count; double activeRatio = totalActiveSeconds * 100.0 / totalDuration; Console.WriteLine($"统计结束,总空闲时长:{Count}秒,总活动时长:{totalActiveSeconds}秒,总统计时长:{totalDuration}秒,活动占比:{activeRatio:F0}%"); Console.ReadLine(); } [DllImport("user32.dll", SetLastError = false)] private static extern bool GetLastInputInfo(ref Lastinputinfo plii); private static readonly DateTime SystemStartup = DateTime.Now.AddMilliseconds(-Environment.TickCount); [StructLayout(LayoutKind.Sequential)] private struct Lastinputinfo { public uint cbSize; public readonly int dwTime; } public static DateTime LastInput => SystemStartup.AddMilliseconds(LastInputTicks); public static TimeSpan IdleTime => DateTime.Now.Subtract(LastInput); private static int LastInputTicks { get { var lii = new Lastinputinfo { cbSize = (uint)Marshal.SizeOf(typeof(Lastinputinfo)) }; GetLastInputInfo(ref lii); return lii.dwTime; } } } }
代码说明
- 变量
Count即为要求的总空闲秒数累计变量,每结束一个时间片就会把该片的空闲值累加进去 - 采样逻辑规避了连续空闲时的重复计数问题:每秒只判断当前这1秒是否属于空闲状态,不会累计连续增长的IdleTime值
- 最终活动占比计算逻辑和示例完全匹配:两个60秒时间片分别累计活动45秒、30秒时,总活动时长75秒,计算得到活动占比为62%。
内容的提问来源于stack exchange,提问作者Nikhil Mahajan
相关产品推荐
相关产品推荐

