66

Is there a simple way to get a system's uptime using C#?

2

10 Answers 10

65
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());
        }
    }
}
6
  • 2
    The first call to uptime.NextValue will return 0.
    – SLaks
    Commented Jun 9, 2009 at 20:12
  • 8
    What if counter name is localized? Commented Mar 5, 2013 at 0:44
  • 5
    Get 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(); Commented Jul 24, 2013 at 0:41
  • 2
    I object that this is 'a simple way'. On top of it, try run it on *nix. Commented May 29, 2017 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)
    – wilson0x4d
    Commented Mar 11, 2018 at 22:15
53

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();
8
  • 1
    @Goby Windows Vista or later? Typo? Renamed “GetTickCount64” to something else?
    – Martin
    Commented Feb 25, 2015 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
    Commented Nov 22, 2015 at 21:25
  • 2
    @rkagerer, wait and see. Short sighted assumptions like those took us to y2k and end of epoch time 2038 =D Commented May 29, 2017 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.
    – wilson0x4d
    Commented Mar 11, 2018 at 21:47
  • 7
    No need to use P/Invoke for this in the most recent .NET versions, as the Environment class now has a TickCount64 property. Commented Mar 2, 2021 at 16:04
31

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.

9
  • 5
    Or, better yet, call TimeSpan.FromMilliseconds
    – SLaks
    Commented Jun 9, 2009 at 19:58
  • 4
    Confusingly, Environment.TickCount returns a number of milliseconds, not .Net ticks (A .Net tick is 100 nanoseconds).
    – SLaks
    Commented Jun 9, 2009 at 20:26
  • 3
    To get ~49.7 days worth of continuity from it, just cast it to a UInt32/uint. Commented Apr 14, 2014 at 4:18
  • 3
    Isn't this a faster and better answer if you really just want uptime? Commented Aug 12, 2014 at 22:36
  • 4
    In the most recent .NET versions the Environment class has a TickCount64 property, which avoids the wrap-around issue. Commented Mar 2, 2021 at 16:06
25

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}");
}
4
  • Thanks for comparing the solutions, please mention compatibility. Which of those solutions will work on non-win platforms? Commented May 29, 2017 at 19:58
  • 1
    ManagementObject 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: stackoverflow.com/a/7407346/382885 Commented Jul 6, 2017 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
    Commented Jul 26, 2017 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
    Commented Feb 20, 2023 at 20:35
16

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);
5
  • 2
    Acquiring high-resolution time stamps 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
    Commented Sep 8, 2014 at 11:58
  • @Martin, do I gather correctly from you that Stopwatch.GetTimestamp() then does not include computer sleep time? Please explain. Commented Jan 12, 2015 at 18:17
  • 1
    I 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
    Commented Jan 12, 2015 at 19:58
  • 1
    This method relies on the system having a HPET so ensure Stopwatch.IsHighResolution is true before using it. See Remarks section of the documentation at msdn.microsoft.com/en-us/library/… Commented May 1, 2017 at 23:17
  • @RyanWilliams, so if there is no HPET, what are the alternatives to get hight precision time? Commented May 13, 2017 at 7:59
15

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);
2
  • 1
    Clean solution. Just be careful: By default in Win 11 "uptime" seems to have changed due to fast startup as discussed here for example Commented Sep 4, 2022 at 20:35
  • This looks like the final answer today - simple, fast, cross-platform Commented Jun 27, 2023 at 20:25
6

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();
}
3
  • 1
    This returns an exception with the message:Invalid object path on Windows 2003 Server running in a web service in IIS6 Commented Jan 11, 2011 at 15:56
  • 2
    This will so amuse you if run on *nix Commented May 29, 2017 at 19:55
  • and start up time ?
    – Kiquenet
    Commented Apr 3, 2019 at 14:08
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!");
    }
1
  • 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. Commented Jun 27, 2023 at 20:23
0

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
  • 3
    TickCount 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. Commented Oct 11, 2013 at 14:22
0

[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.
  */
5
  • I'm not sure what you mean by "You definitely want to avoid P/Invoke overhead." Using [DllImport] is using P/Invoke, surely? Commented Mar 2, 2021 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. Commented Mar 3, 2021 at 12:12
  • Interesting. Do you have a link for that? The best I could find was this which states "SafeNativeMethods - This class suppresses stack walks for unmanaged code permission." Commented Mar 3, 2021 at 14:06
  • Interesting trick, but I'd advise against it. .net is not a windows only framework, right? Commented Jun 27, 2023 at 20:20
  • Agreed. Completely superceded by the new Environment.TickCount64, I think. Or the Stopwatch class. Commented Jun 27, 2023 at 23:44

Not the answer you're looking for? Browse other questions tagged or ask your own question.