使用 C# 检索系统正常运行时间

发布于 2024-07-24 02:28:47 字数 37 浏览 8 评论 0原文

有没有一种简单的方法可以使用 C# 获取系统的正常运行时间?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

巡山小妖精 2024-07-31 02:28:47
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());
        }
    }
}
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());
        }
    }
}
锦爱 2024-07-31 02:28:47

我有点晚了,但另一种简单方法是使用GetTickCount64 函数,该函数从 Windows Vista 开始可用,并且不会像 GetTickCount 那样溢出:

public static TimeSpan GetUpTime()
{
    return TimeSpan.FromMilliseconds(GetTickCount64());
}

[DllImport("kernel32")]
extern static UInt64 GetTickCount64();

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();
幸福不弃 2024-07-31 02:28:47

System.Environment.TickCount 获取自此以来的毫秒数系统已重新启动。

但请注意,它是 Int32,并且会在 24.9 天后溢出并变为负值。 请参阅 MDSN 文档上的注释。

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.

我的黑色迷你裙 2024-07-31 02:28:47

根据任务管理器,我的机器的正常运行时间为 58 天 17 小时。 我浏览并尝试了这里的每个答案,快速的答案稍有偏差(大约 1-3 分钟,但正常运行时间超过 58 天):

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

最后两个,使用 PerformanceCounter 或使用 ManagementObject,总是在同一秒内作为 Windows 任务管理器(只需相信我的话,或者使用下面的代码自行尝试)。 根据结果​​,我将使用 ManagementObject LastBootUpTime 方法,因为它比 PerformanceCounter 快得多,但与任务管理器相比仍然非常准确。

请注意,在打印时间之前,我确实从每个方法中减去了当前经过的时间,但整个过程的运行时间不到 2 秒,因此无论如何都不能通过不正确地计算执行时间来解释时间偏移。 这是我使用的代码:

[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}");
}

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}");
}
话少情深 2024-07-31 02:28:47

比 System.Environment.TickCount 更精确且更大,不涉及操作系统可怕的性能计数器、WMI 或本机调用:

var ticks = Stopwatch.GetTimestamp();
var uptime = ((double)ticks) / Stopwatch.Frequency;
var uptimeSpan = TimeSpan.FromSeconds(uptime);

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);
疏忽 2024-07-31 02:28:47

如果您使用的是更高版本的 .NET(Core 3.0/.NET 5.0 或更高版本),则 Environment 类现在具有 TickCount64 属性

这不会受到 TickCount 属性的环绕问题的影响,您也不必求助于 P/Invoke 来获取该值。

long tickCountMs = Environment.TickCount64;
var uptime = TimeSpan.FromMilliseconds(tickCountMs);

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);
青芜 2024-07-31 02:28:47

最简单且正确的方法是

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();
}

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();
}
烧了回忆取暖 2024-07-31 02:28:47

简单,不,但可以做到:

    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!");
    }

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!");
    }
≈。彩虹 2024-07-31 02:28:47

我知道问题既古老又已解决,但我能想到的最有效的解决方案就是使用 Enviroment.TickCount 属性,它返回自系统启动以来的毫秒数:

System.DateTime SystemStartTime = DateAndTime.Now.AddMilliseconds(-Environment.TickCount);
System.DateTime Uptime = DateAndTime.Now - SystemStartTime;

此解决方案比公认的答案快得多。

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.

櫻之舞 2024-07-31 02:28:47

[编辑:] 现在完全没有必要了,因为 .net 已经有了 Environment.TickCount64 (或 Stopwatch 类)。 请忽略。

(唯一的)正确答案,[编辑:很久以前在一个很远的地方:]

使用 32 位定时器非常危险,并且除了有限的使用之外,很容易出错。

我不确定 NativeMethods 类的内容何时被添加到 .net 中,但确实如此。 您肯定希望避免 P/Invoke 开销。 做这个:

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.
  */

[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.
  */
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文