Is there a simple way to get a system's uptime using C#?
-
2dup: http://stackoverflow.com/questions/265089/how-to-get-the-up-time-of-the-machine/265101#265101 – Inisheer Jun 09 '09 at 20:06
-
1I just wanted to say that the uptime nowadays might appear much longer, since systems no longer shut down but hibernate instead (Windows 10) – Thomas Weller Dec 27 '19 at 13:39
10 Answers
public TimeSpan UpTime {
get {
using (var uptime = new PerformanceCounter("System", "System Up Time")) {
uptime.NextValue(); //Call this an extra time before reading its value
return TimeSpan.FromSeconds(uptime.NextValue());
}
}
}

- 868,454
- 176
- 1,908
- 1,964
-
2
-
8
-
5Get localised names (2 = System, 674 = System Up Time) using: `StringBuilder buffer = new StringBuilder(1024); uint buf_size = (uint)buffer.Capacity; Win32.PdhLookupPerfNameByIndex(null, id, buffer, ref buf_size); return buffer.ToString();` – Oliver Bock Jul 24 '13 at 00:41
-
2I object that this is 'a simple way'. On top of it, try run it on *nix. – Robert Cutajar May 29 '17 at 19:47
-
1@Rbjz usually qualifying an answer with "using C#" means the OP is not looking for an answer that requires anything not already present in the .NET Framework. As of 2009 this was the simplest C# method for acquiring a non-overflowing "uptime" -- alternatives included querying WMI and scanning the System Event Log for a boot record.. and by comparison this method is the "simplest" and would work over all versions of Windows supported by .NET Not "using C#" requires PInvoke; `GetTickCount64` (not in all Windows vers) or `ZwQuerySystemInformation` (undoc), or `sysinfo` (on posix+SVR4 systems) – Shaun Wilson Mar 11 '18 at 22:15
-
This function does not return the Uptime, it returns the duration between last restart and now. Turning the computer on and of does not affect this behaviour. – Guido Kleijer Jul 31 '19 at 21:08
I'm a bit late, but another simple way is to use the GetTickCount64 function, which is available starting with Windows Vista and does not overflow as GetTickCount does:
public static TimeSpan GetUpTime()
{
return TimeSpan.FromMilliseconds(GetTickCount64());
}
[DllImport("kernel32")]
extern static UInt64 GetTickCount64();

- 1,986
- 15
- 32
-
This was exactly what I needed, thank you much for posting this :) – Tom Anderson Jul 02 '13 at 17:15
-
GetTickCount64() returns error "the System.EntryPointNotFoundException: Unable to find an entry point". – Lin Song Yang Feb 24 '15 at 00:22
-
1@Goby Windows Vista or later? Typo? Renamed “GetTickCount64” to something else? – Martin Feb 25 '15 at 15:33
-
13`GetTickCount64 ... does not overflow` - It will overflow when they find a way to make my code run for 585 billion years – rkagerer Nov 22 '15 at 21:25
-
2@rkagerer, wait and see. Short sighted assumptions like those took us to y2k and end of epoch time 2038 =D – Robert Cutajar May 29 '17 at 19:54
-
1@Rbjz y2k wasn't nearly as eventful as it is made out to be, just as well these APIs aren't built on "assumptions" they are built on "hardware limits"; `GetTickCount` is a performance API calculated from kernel structures that were 32bit at the time, `GetTickCount64` surfaced after those kernel structures supported 64bit values. Might be worth noting that `GetTickCount` was originally meant to provide time correlation between system performance counters over a short period, a use which was later superceded by `QueryPerformanceCounter` for higher resolution correlation over a longer period. – Shaun Wilson Mar 11 '18 at 21:47
-
6No need to use P/Invoke for this in the most recent .NET versions, as the **Environment** class now has a [`TickCount64` property](https://learn.microsoft.com/en-us/dotnet/api/system.environment.tickcount64?view=net-5.0). – Steven Rands Mar 02 '21 at 16:04
-
@StevenRands Would you like to post a new answer with `Environment.TickCount64`? I think this is now the "best" solution. – Martin Mar 03 '21 at 11:42
System.Environment.TickCount gets the number of milliseconds since the system was restarted.
Beware though that it is an Int32 and will overflow after 24.9 days and will become negative. See the remarks on the MDSN docs.

- 81,306
- 22
- 176
- 206
-
1To be pedantic, convert that property to milliseconds with TimeSpan.TicksPerMillisecond (http://msdn.microsoft.com/en-us/library/system.timespan.tickspermillisecond.aspx) – Michael Petrotta Jun 09 '09 at 19:52
-
5
-
@SlLaks - am I missing something? You've got to get milliseconds from ticks before you can get a TimeSpan from milliseconds. – Michael Petrotta Jun 09 '09 at 20:03
-
-
4Confusingly, Environment.TickCount returns a number of milliseconds, not .Net ticks (A .Net tick is 100 nanoseconds). – SLaks Jun 09 '09 at 20:26
-
-
2To get ~49.7 days worth of continuity from it, just cast it to a `UInt32`/`uint`. – Slipp D. Thompson Apr 14 '14 at 04:18
-
3Isn't this a faster and better answer if you really just want uptime? – Chibueze Opata Aug 12 '14 at 22:36
-
2In the most recent .NET versions the **Environment** class has a [`TickCount64` property](https://learn.microsoft.com/en-us/dotnet/api/system.environment.tickcount64?view=net-5.0), which avoids the wrap-around issue. – Steven Rands Mar 02 '21 at 16:06
-
Cannot be recommended to anyone serious due to the overflow. Please don't use it. – Robert Cutajar Jun 27 '23 at 20:31
My machine has an uptime of 58 days 17 hours
according to Task Manager. I went through and tried each answer here and the fast ones are off by a little bit (~1-3 minutes roughly, but over 58 days of uptime):
Stopwatch.GetTimeStamp(): 58days 17hours 11minutes 25seconds
~Time to calculate (ms): 6.8413
DllImport GetTickCount64(): 58days 17hours 13minutes 34seconds
~Time to calculate (ms): 0.2192
PerformanceCounter(System, System Up Time): 58days 17hours 14minutes 02seconds
~Time to calculate (ms): 1233.2854
ManagementObject LastBootUpTime: 58days 17hours 14minutes 02seconds
~Time to calculate (ms): 30.0283
The last two, using PerformanceCounter or using ManagementObject, are always within the same second as Windows Task Manager (just have to take my word for it, or try it yourself with the code below). Based on the results I am going to use the ManagementObject LastBootUpTime
method because it's drastically faster than the PerformanceCounter
but is still perfectly accurate when compared to Task Manager.
Note that I did subtract the current elapsed time from each method before printing the times, but the whole thing takes less than 2 seconds to run so the time shift can't be explained by improperly accounting for execution time anyway. Here's the code I used:
[System.Runtime.InteropServices.DllImport("kernel32")]
extern static UInt64 GetTickCount64();
public static void Main()
{
var start = Stopwatch.StartNew();
var eachStart = Stopwatch.StartNew();
var ticks = Stopwatch.GetTimestamp();
var uptime = ((double)ticks) / Stopwatch.Frequency;
var uptimeTimeSpan = TimeSpan.FromSeconds(uptime);
Console.WriteLine("Stopwatch.GetTimeStamp(): " + uptimeTimeSpan.Subtract(start.Elapsed).ToString(@"dd\d\a\y\s\ hh\h\o\u\r\s\ mm\m\i\n\u\t\e\s\ ss\s\e\c\o\n\d\s"));
Console.WriteLine($"~Time to calculate (ms): {eachStart.Elapsed.TotalMilliseconds}");
eachStart.Restart();
Console.WriteLine("DllImport GetTickCount64(): " + TimeSpan.FromMilliseconds(GetTickCount64()).Subtract(start.Elapsed).ToString(@"dd\d\a\y\s\ hh\h\o\u\r\s\ mm\m\i\n\u\t\e\s\ ss\s\e\c\o\n\d\s"));
Console.WriteLine($"~Time to calculate (ms): {eachStart.Elapsed.TotalMilliseconds}");
eachStart.Restart();
var upTime = new PerformanceCounter("System", "System Up Time");
upTime.NextValue(); //Call this an extra time before reading its value
Console.WriteLine("PerformanceCounter(System, System Up Time): " + TimeSpan.FromSeconds(upTime.NextValue()).Subtract(start.Elapsed).ToString(@"dd\d\a\y\s\ hh\h\o\u\r\s\ mm\m\i\n\u\t\e\s\ ss\s\e\c\o\n\d\s"));
Console.WriteLine($"~Time to calculate (ms): {eachStart.Elapsed.TotalMilliseconds}");
eachStart.Restart();
ManagementObject mo = new ManagementObject(@"\\.\root\cimv2:Win32_OperatingSystem=@");
DateTime lastBootUp = ManagementDateTimeConverter.ToDateTime(mo["LastBootUpTime"].ToString());
Console.WriteLine("ManagementObject LastBootUpTime: " + (DateTime.Now.ToUniversalTime() - lastBootUp.ToUniversalTime()).Subtract(start.Elapsed).ToString(@"dd\d\a\y\s\ hh\h\o\u\r\s\ mm\m\i\n\u\t\e\s\ ss\s\e\c\o\n\d\s"));
Console.WriteLine($"~Time to calculate (ms): {eachStart.Elapsed.TotalMilliseconds}");
}
-
Thanks for comparing the solutions, please mention compatibility. Which of those solutions will work on non-win platforms? – Robert Cutajar May 29 '17 at 19:58
-
1ManagementObject code using "\\.\root\cimv2:Win32_OperatingSystem=@" doesn't work on Windows XP because apparently Win32_OperatingSystem is not a singleton on XP. Instead I found that I needed to use a query to find the primary instance and loop over the query results, as demonstrated in this answer which worked for me on both XP and Win 7: https://stackoverflow.com/a/7407346/382885 – PolyTekPatrick Jul 06 '17 at 11:54
-
Great answer. Thanks ! I just wanted to add two things : GetTickCount64() is not supported on versions of Windows before Vista, and PerformanceCounter("System", "System Up Time") takes REALLY long on my W7 laptop (more than one minute. Don't ask why.) – AFract Jul 26 '17 at 12:52
-
If you use @"dd\ \d\a\y\s\,\ hh\ \h\o\u\r\s\,\ mm\ \m\i\n\u\t\e\s\,\ ss\ \s\e\c\o\n\d\s", it spaces things out nicely. "26 days, 05 hours, 32 minutes, 48 seconds" – B E Feb 20 '23 at 20:35
Precise and bigger than System.Environment.TickCount
, not involving OS horrific perf counters, WMI or native calls:
var ticks = Stopwatch.GetTimestamp();
var uptime = ((double)ticks) / Stopwatch.Frequency;
var uptimeSpan = TimeSpan.FromSeconds(uptime);

- 3,181
- 1
- 30
- 42
-
2[Acquiring high-resolution time stamps](http://msdn.microsoft.com/en-us/library/windows/desktop/dn553408%28v=vs.85%29.aspx) explains why this returns the uptime: “QueryPerformanceCounter [...] returns the total number of ticks that have occurred since the Windows operating system was started, including the time when the machine was in a sleep state such as standby, hibernate, or connected standby.” – Martin Sep 08 '14 at 11:58
-
@Martin, do I gather correctly from you that `Stopwatch.GetTimestamp()` then does not include computer sleep time? Please explain. – Robert Cutajar Jan 12 '15 at 18:17
-
1I only cited from the article to which I linked, I didn't write it ;-) In that article: “In this context, the term tick refers to a period of time equal to 1 ÷ (the frequency of the performance counter obtained from QueryPerformanceFrequency)”. I’d understand that a tick simply is a unit of time, as is e.g. a “second”, and it seems to me that this is how the word “tick” is used throughout the article. Thus, the computer does not need to run to make “ticks” “occur”, and `GetTimestamp()` _does_ include sleep time. But I do not know the definitive answer to your question. – Martin Jan 12 '15 at 19:58
-
1This method relies on the system having a HPET so ensure Stopwatch.IsHighResolution is true before using it. See Remarks section of the documentation at https://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.gettimestamp(v=vs.110).aspx – Ryan Williams May 01 '17 at 23:17
-
@RyanWilliams, so if there is no HPET, what are the alternatives to get hight precision time? – Robert Cutajar May 13 '17 at 07:59
If you are using a later .NET version (Core 3.0/.NET 5.0 or above), then the Environment
class now has a TickCount64 property.
This doesn't suffer from the wrap-around issues of the TickCount
property, nor do you have to resort to P/Invoke to get the value.
long tickCountMs = Environment.TickCount64;
var uptime = TimeSpan.FromMilliseconds(tickCountMs);

- 5,160
- 3
- 27
- 56
-
Clean solution. Just be careful: By default in Win 11 "uptime" seems to have changed due to fast startup as discussed [here](https://techcommunity.microsoft.com/t5/windows-11/win-11-shut-down-button-is-not-restting-uptime-get-uptime-is/m-p/3268351/highlight/true#M3083) for example – Simon Opelt Sep 04 '22 at 20:35
-
This looks like the final answer today - simple, fast, cross-platform – Robert Cutajar Jun 27 '23 at 20:25
The simplest and proper way to do this is
public static TimeSpan GetUptime()
{
ManagementObject mo = new ManagementObject(@"\\.\root\cimv2:Win32_OperatingSystem=@");
DateTime lastBootUp = ManagementDateTimeConverter.ToDateTime(mo["LastBootUpTime"].ToString());
return DateTime.Now.ToUniversalTime() - lastBootUp.ToUniversalTime();
}

- 597
- 5
- 10
-
1This returns an exception with the message:`Invalid object path` on Windows 2003 Server running in a web service in IIS6 – Hugh Jeffner Jan 11 '11 at 15:56
-
2
-
Simple, no but it can be done:
static DateTime getLastBootTime(ManagementObject mObject)
{
PropertyData pd = mObject.Properties["LastBootUpTime"];
string name = pd.Name.ToString();
DateTime lastBoot = parseCmiDateTime(pd.Value.ToString());
return lastBoot;
}
static ManagementObject getServerOSObject(string serverName)
{
ManagementObjectSearcher mSearcher = new ManagementObjectSearcher("Select * From Win32_OperatingSystem");
mSearcher.Scope = new ManagementScope(String.Format(@"\\{0}\root\cimv2", serverName));
ManagementObjectCollection mObjects = mSearcher.Get();
if (mObjects.Count != 1) throw new Exception(String.Format("Expected 1 object, returned {0}.", mObjects.Count));
foreach (ManagementObject m in mObjects)
{
//No indexing on collection
return m;
}
throw new Exception("Something went wrong!");
}

- 31,137
- 42
- 147
- 238
-
As the question really asks for a simple solution, this is not a correct answer. It is interesting for completeness, though. And won't work outside of windows and even there the compatibility is questionable. – Robert Cutajar Jun 27 '23 at 20:23
I know question is both old and solved, but the esiest solution I can tink of is just using the Enviroment.TickCount property, which returns the number of millisecounds since the system started:
System.DateTime SystemStartTime = DateAndTime.Now.AddMilliseconds(-Environment.TickCount);
System.DateTime Uptime = DateAndTime.Now - SystemStartTime;
This solition is a lot faster than the accepted answare.

- 1,064
- 9
- 14
-
3TickCount is returned as an integer but the system timer has more resolution so there is an extended period of time where the tick count is int.MaxValue, and then eventually it goes down to int.MinValue. This method is not useful for servers that are up for months at a time. Technically system timer resolution is also only accurate up to blocks of 10 to 16 milliseconds. – TheXenocide Oct 11 '13 at 14:22
[edit: ] Completely unnecessary now that .net has Environment.TickCount64
(or the Stopwatch
class). Please disregard.
The (one and only) correct answer, [edit: a long time ago in a place far far away: ]
Using the 32-bit timer is incredibly dangerous, and prone to error for all but limited use.
I'm not sure when the NativeMethods class stuff was added to .net, but it was. You definitely want to avoid P/Invoke overhead. Do this:
using System;
using System.Runtime.InteropServices;
namespace Mu
{
// prevents PInvoke (not in NativeMethods class) or Stack walk (NativeMethods class) performance penalties.
internal static partial class SafeNativeMethods
{
[DllImport("kernel32")]
internal extern static UInt64 GetTickCount64();
}
public static class MuTime
{
public static UInt64 UpTimeMillis { get { return SafeNativeMethods.GetTickCount64(); } }
}
}
/*
Dual License (use either, not both). To avoid CC-BY-SA, access a copy of this
code at (https://pastebin.com/6EKTWsSf) to use under BSD 0-clause license,
Copyright (c) 2020 Robin Davies
CC-BY-SA 3.0 (due to StackExchange terms of use). Not my fault, blame StackExchange. Fix this
please, StackExchange!
BSD 0-Clause
Copyright 2020 Robin Davies.
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
*/

- 7,547
- 1
- 35
- 50
-
I'm not sure what you mean by _"You definitely want to avoid P/Invoke overhead."_ Using `[DllImport]` _is_ using P/Invoke, surely? – Steven Rands Mar 02 '21 at 16:15
-
Methods that don't require marshalling are called directly, *IF* they are included in a class named SafeNativeMethods. A feature that crept into .net somewhere in the 4.x timeframe. – Robin Davies Mar 03 '21 at 12:12
-
Interesting. Do you have a link for that? The best I could find was [this](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1060) which states _"SafeNativeMethods - This class suppresses stack walks for unmanaged code permission."_ – Steven Rands Mar 03 '21 at 14:06
-
Interesting trick, but I'd advise against it. .net is not a windows only framework, right? – Robert Cutajar Jun 27 '23 at 20:20
-
Agreed. Completely superceded by the new Environment.TickCount64, I think. Or the Stopwatch class. – Robin Davies Jun 27 '23 at 23:44