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

时间:2009-06-09 19:42:01

标签: c# .net windows uptime

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

10 个答案:

答案 0 :(得分:52)

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

答案 1 :(得分:37)

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

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

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

答案 2 :(得分:26)

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

请注意,它是一个Int32,并会在24.9天后溢出并且会变为负数。请参阅MDSN文档上的备注。

答案 3 :(得分:17)

根据任务经理的说法,我的机器的正常运行时间为58 days 17 hours。我经历过并尝试了每个答案,而快速的答案有点偏差(约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}");
}

答案 4 :(得分:10)

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

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

答案 5 :(得分:7)

最简单和正确的方法是

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

答案 6 :(得分:4)

简单,不,但可以做到:

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

答案 7 :(得分:3)

如果您使用的是更高版本的 .NET(Core 3.0/.NET 5.0 或更高版本),那么 Environment 类现在有一个 TickCount64 property

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

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

答案 8 :(得分:1)

我知道问题既旧又解决了,但我能说的最好的解决办法就是使用Enviroment.TickCount属性,该属性返回自系统启动以来的毫秒数:

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

这个解决方案比被接受的answare快得多。

答案 9 :(得分:1)

到目前为止(唯一的)正确答案:

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