Environment.TickCount is not enough
Solution 1
public void BootTime(){
SelectQuery query = new SelectQuery("SELECT LastBootUpTime FROM Win32_OperatingSystem WHERE Primary='true'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
foreach (ManagementObject mo in searcher.Get())
{
DateTime dtBootTime = ManagementDateTimeConverter.ToDateTime(mo.Properties["LastBootUpTime"].Value.ToString());
Console.WriteLine(dtBootTime.ToString());
}
}
Solution 2
The following code retrieves the milliseconds since system start (call to unmanged API). I measured the performance costs for that interop operation, and it is quite identical to StopWatch() (but that doesn't retrieve the time since system start directly of course).
using System.Runtime.InteropServices;
...
[DllImport("kernel32.dll") ]
public static extern UInt64 GetTickCount64();
...
var tickCount64 = GetTickCount64();
https://msdn.microsoft.com/de-de/library/windows/desktop/ms724411(v=vs.85).aspx
Solution 3
You're correct that Environment.TickCount
will overflow after approximately 25 days, because the return value is a 32-bit integer.
But there's a better way than trying to compare the TickCount
if you want to determine when the system was last started. What you're looking for is called the system up-time. There are a couple of different ways that you can retrieve this.
The easiest way is to use the PerformanceCounter
class (in the System.Diagnostics
namespace), which lets you query a particular system performance counter. Try the following code:
TimeSpan upTime;
using (var pc = new PerformanceCounter("System", "System Up Time"))
{
pc.NextValue(); //The first call returns 0, so call this twice
upTime = TimeSpan.FromSeconds(pc.NextValue());
}
Console.WriteLine(upTime.ToString());
Alternatively, you can do this through WMI. But it looks like stian.net's answer has that covered.
Note, finally, that the performance counter's name must be localized if you need to support international versions of Windows, so the correct solution must look up the localized strings for "System" and "System Up Time" using PdhLookupPerfNameByIndex, or you must ensure you are using the PdhAddEnglishCounter under the hood, which is only supported in Vista or higher. More about this here.
codebased
Amit Malhotra is a Software Engineer at Commonwealth Bank of Australia. He has an extensive experience in software architecture, design and develop, using agile approach. Amit is an expert in application development in Cloud architecture and development with Microsoft technologies such as .NET, C#, Microsoft Dynamics. He also interact with various open source frameworks such as AngularJS, EmberJS. His work involves Service Oriented Architecture (SOA) using REST, Database Design, Android technologies. Amit is Agile Certified developer. Amit has done MCA from National Institute of Electronics & Information Technology (NIELIT), (erstwhile DOEACC Society). Twit him on @imcodebased
Updated on June 22, 2022Comments
-
codebased almost 2 years
I want to know on when was the last time the system was started.
Environment.TickCount will work but it is breaking after 48-49 days because of the limitation of int.
This is the code I've been using:
Environment.TickCount & Int32.MaxValue
Does anyone knows about long type return somehow?
I am using this to know the idle time of the system:
public static int GetIdleTime() { return (Environment.TickCount & Int32.MaxValue)- (int)GetLastInputTime(); } /// <summary> /// Get the last input time from the input devices. /// Exception: /// If it cannot get the last input information then it throws an exception with /// the appropriate message. /// </summary> /// <returns>Last input time in milliseconds.</returns> public static uint GetLastInputTime() { LastInputInfo lastInPut = new LastInputInfo(); lastInPut.BlockSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(lastInPut); if (!GetLastInputInfo(ref lastInPut)) { throw new Exception(GetLastError().ToString()); } return lastInPut.Time; }
-
stian.net over 13 yearsYou need reference to System.Management
-
stian.net over 13 yearsok, so you can write Console.WriteLine(DateTime.Now - upTime); and get the right date :) But i would still use WMI. On my system PerformanceCounter used 2 sec to display up-time. WMI used 40 ms
-
Cody Gray over 13 years@stian: Fair enough.
PerformanceCounter
is probably the "official" .NET way, and it seemed unlikely to me that this was something worth optimizing, given it's not going to be called in a loop. But I agree WMI may well be the better option, and I even suggested its use in my answer. -
Martin Liversage over 13 yearsInitially I found it rather surprising that using performance counters would be slow given the purpose of that part of Windows. However, on my computer the call to
new PerformanceCounter
loads no less than 80 DLL's! This takes quite some time but it is a one time only cost and after that performance counters appear to be, well, performing very well. -
Cody Gray over 13 years@Martin: Good work testing that out. I was wondering the same thing. That's really an incredible number for what seems like such a simple task. Retrieving the information from running
net statistics workstation
at the command prompt doesn't take anywhere near that long. -
codebased over 13 yearsThank you guys... the problem is coming with GetLastInputTime(...) as it is still returning integer. Is any way the tick time I can receive on when the last input was? If I am getting long, milliseconds, then I would also want to know how GetLastInputTime(...) ?
-
codebased over 13 yearsLet me rephase here... is there any way about to get the total idle time with at least in long tick(milliseconds). This idle time means that the System UP - Last Input received. With above, I could managed to get the System up time in long, however the last input received is calculating per the uint so after 48 days it will bust.
-
codebased over 13 yearsYeah that is what am using:internal struct LASTINPUTINFO { public uint cbSize; public uint dwTime; } you can see dwTime is uint.
-
Enigmativity almost 9 yearsDo make sure that you dispose the ManagementObjectSearcher instance.
-
Josh over 8 yearsThis is not even close to an applicable answer to the OP's question.
-
Boogier over 4 yearsWMI can be disabled on a computer and this code won't work.