C#, Tools – PC Time to track on/off time of computer

One boring task at my company is that each employee should report how he allocates time for each project he was following. Of course it is a must-do-work for project managers or supporters because they have to monitor how much time they have worked for each project so that the accounting department can send billings to customers later. But it doesn’t mean to me because I am a programmer and I have only 2 or 3 projects to take care of. I am just swinging between 2 phases: developing and bug fixing. The Test-phase will be made by Testers. Sometimes I write some Unit-Tests too but it’s not my fulltime field. As you see, my tasks are pretty “simple” however I must make myself an hour booking report at the end of each month too.
So I try to keep this task as simple as it is. Each day I make a notice on my calendar about with which project I am on. For a small, short-time project, I notice its name and its duration. It works great. But for a long-time project then I really don’t know how long I was on because it takes weeks, months to accomplish. The problem is that I always forget to book hours after working day. Then I have an idea to approximate my PC on time as project time (Of course I have to subtract lunch pause and some minutes for short break) It won’t be exact as project time but I believe it will be nearly exact. With this solution I don’t need to remember to book hour after each day anymore.
To monitor PC on/off time there is also half-free software on Internet, you can easily find him with search engine. In free version, I can only see 3 weeks before today. If I want to see more, I must buy a PRO-version. I am a poor man so I don’t have money to buy one therefore I must write myself to help me making my hour booking report.
The tool is not very complicated because any action of computer was logged by operating system. The On/Off events are not exceptions. I just have to read them out from log files and show them in easy-read way. Every time when I turn the computer on/off, the actions will be logged in Windows Logs –> System which can be viewed through Event Viewer

Windows Logs System

As you can see in image above (in case that you can read German ^_^), Event-ID 12 is ID of ON-Event which was sent by Kernel when I turn the computer on. The OFF-Event has ID 13. So basing on this log, I can trace back when I switch my computer on/off, calculate the ON time, make some magical calculations and then I have my project time at last. I will show you how to read on/off time from this log with C#.

Dictionary<DateTime, List<TimeBlock>> PCOnOffTime = new Dictionary<DateTime, List<TimeBlock>>();
private void IntializeData()
{
	EventLog log = new EventLog();
	log.Log = "System";
	log.MachineName = ".";

	var entries = log.Entries.Cast<EventLogEntry>();
	var itemMin = from e in entries
				  group e by e.TimeGenerated.Date into g
				  select new CustomEntry { EntryDate = g.Key, TimeGenerated = g.Min(e => e.TimeGenerated), ActionType = "On" };
	var itemMax = from e in entries
				  group e by e.TimeGenerated.Date into g
				  select new CustomEntry { EntryDate = g.Key, TimeGenerated = g.Max(e => e.TimeGenerated), ActionType = "Off" };
	var itemOn = from e in entries
				 where e.InstanceId == 12 && e.Source.Contains("Kernel-General") && e.EntryType == EventLogEntryType.Information
				 select new CustomEntry { EntryDate = e.TimeGenerated.Date, TimeGenerated = e.TimeGenerated, ActionType = "On" };
	var itemOff = from e in entries
				  where e.InstanceId == 13 && e.Source.Contains("Kernel-General") && e.EntryType == EventLogEntryType.Information
				  select new CustomEntry { EntryDate = e.TimeGenerated.Date, TimeGenerated = e.TimeGenerated, ActionType = "Off" };


	List<CustomEntry> temp = new List<CustomEntry>();
	itemMin.ToList().ForEach(x => temp.Add(x));
	itemMax.ToList().ForEach(x =>
	{
		if (temp.FirstOrDefault(y => y.TimeGenerated == x.TimeGenerated) == null)
			temp.Add(x);
	});
	itemOn.ToList().ForEach(x =>
	{
		if (temp.FirstOrDefault(y => y.TimeGenerated == x.TimeGenerated) == null)
			temp.Add(x);
	});
	itemOff.ToList().ForEach(x =>
	{
		if (temp.FirstOrDefault(y => y.TimeGenerated == x.TimeGenerated) == null)
			temp.Add(x);
	});

	List<CustomEntry> result = new List<CustomEntry>();
	string actionType = "";
	CustomEntry itemBefore = null;
	foreach (CustomEntry item in temp.Distinct().OrderBy(x => x.TimeGenerated))
	{
		if (actionType == item.ActionType)
			result.Remove(itemBefore);
		result.Add(item);
		actionType = item.ActionType;
		itemBefore = item;
	}

	for (int index = 0; index < result.Count; index++)
	{
		if (!PCOnOffTime.ContainsKey(result[index].EntryDate))
		{
			List<TimeBlock> listTimeBlocks = new List<TimeBlock>();
			PCOnOffTime.Add(result[index].EntryDate, listTimeBlocks);
		}

		PCOnOffTime[result[index].EntryDate].Add(new TimeBlock() { EntryStartTime = result[index].TimeGenerated, EntryEndTime = result[++index].TimeGenerated });
	}
}

The code is pretty simple. I just instantiate a variable whose type is EventLog, indicate it to work with the System-Log at my local machine (MachineName = “.”). Then I read the first entry of each day and set it as ON action and last entry of each day and set it as OFF action. Now I have a likely ON duration but it will be wrong if I turn on the computer in the morning at 8:00, turn it off at 8:15, go out, come back to company at 17:00, turn computer on again and turn it off at 17:15. Then the first entry is 8:00 and the last is 17:15 but the truth is I am not in company during this time. So I have to catch the ON/OFF events within day as in variables itemOn/itemOff.
After having all ON/OFF events, I just add them together, order ascending according to time, remove duplicated ones and then construct them in a Dictionary whose Key is date and Value is a list of time block marked with On and Off time. That means in one date, computer can be turned on/off many times. These on/off time will be parsed as EntryStartTime/EntryOffTime and saved in list.

class CustomEntry
{
	public DateTime EntryDate { get; set; }
	public DateTime TimeGenerated { get; set; }
	public string ActionType { get; set; }
}
class TimeBlock
{
	public DateTime EntryStartTime { get; set; }
	public DateTime EntryEndTime { get; set; }
}

At the end is the GUI. With some mock-up from WPF, I have beautiful PC Time software to show me when I turned on/off my computer.

PC Time On Loading

PC Time Load Finished

Maybe you’ll tell me that you can let the computer on and go out. My tool cannot detect that. Yes, it’s true but this tool is to help you to control yourself, not to cheat someone else. 😀
Binary: http://hintdesk.com/Web/Tool/PC%20Time.zip
Source code: https://bitbucket.org/hintdesk/dotnet-tools-pc-time-to-track-onoff-time-of-computer