Environment.TickCount是不够的

时间:2011-01-10 09:12:40

标签: c# .net c#-4.0 environment-variables gettickcount

我想知道系统最后一次启动的时间。

Environment.TickCount会有效,但由于int的限制,它会在48-49天后破坏。

这是我一直在使用的代码:

Environment.TickCount & Int32.MaxValue

有人知道长型返回吗?

我用它来了解系统的空闲时间:

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

6 个答案:

答案 0 :(得分:8)

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

答案 1 :(得分:6)

你认为Environment.TickCount在大约25天后会溢出是正确的,因为返回值是32位整数。

但如果您想确定系统上次启动的时间,那么有一种比尝试比较TickCount更好的方法。您正在寻找的是系统正常运行时间。您可以通过几种不同的方式检索此内容。

最简单的方法是使用PerformanceCounter class(在System.Diagnostics命名空间中),这样可以查询特定的系统性能计数器。请尝试以下代码:

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

或者,您可以通过WMI执行此操作。但看起来stian.net's answer已经覆盖了。

最后请注意,如果您需要支持国际版本的Windows,则必须对性能计数器的名称进行本地化,因此正确的解决方案必须使用{{3}查找“系统”和“系统运行时间”的本地化字符串或者,您必须确保使用引擎盖下的PdhLookupPerfNameByIndex,这仅在Vista或更高版本中受支持。有关此PdhAddEnglishCounter的更多信息。

答案 2 :(得分:5)

以下代码检索自系统启动以来的毫秒数(调用unmanged API)。我测量了该互操作的性能成本,它与StopWatch()完全相同(但是,当然直接从系统启动开始检索时间)。

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

答案 3 :(得分:0)

如果计算每个环绕声,您可以制作自己的64位TickCount,适用于2 ^ 63 ms(2.92亿年)或2 ^ 64 ms(5.85亿年)。如果您不需要完整的1ms精度(实际上只有10-16ms分辨率)或范围,您可以将结果除以1000并表示最多49,710天(136年),分辨率为1秒,在UInt32的。

docker exec -it container_name mynewscript为您执行此操作,但仅适用于Vista或更高版本。

这里我计算经过时间的总结,而不是TickCount。

GetTickCount64()

使用Int32.MaxValue进行AND操作是不必要的,也是.NET文档中的一个不好的例子。未经检查的32位整数减法安全溢出。 Environment.TickCount的标志永远不重要。减法处理所有环绕的情况。示例,由一个环绕:uiT0 = Int32.MaxValue; iTickNow = uiT0 + 1产生Int32.MinValue;最后,(iTickNow - uiT0)产生1。

uiElapsed轨道经过的时间一直到它包裹到零之前的49.7天。每次包装时,iWrapCount都会递增。 GetElapsedTime()必须每49.7天至少调用一次,这样就不会检测到环绕声。

答案 4 :(得分:-1)

我认为这只是他们实施它的方式。

从0到最大,然后从min到0。

https://msdn.microsoft.com/en-us/library/system.environment.tickcount(v=vs.110).aspx

我已经从http://www.codeproject.com/Articles/13384/Getting-the-user-idle-time-with-C

编辑了您正在使用的代码

为什么不直接获得绝对数字?

    Public Shared Function GetIdle() As UInteger
        Dim lii As New LASTINPUTINFO()
        lii.cbSize = Convert.ToUInt32((Marshal.SizeOf(lii)))
        GetLastInputInfo(lii)

        Dim totalTicks As Long = 0

        If Environment.TickCount > 0 Then
            totalTicks = Convert.ToUInt64(Environment.TickCount)
        Else
            totalTicks = Convert.ToUInt64(Environment.TickCount * -1)
        End If

        Return Math.Abs(totalTicks - lii.dwTime)

    End Function

答案 5 :(得分:-1)

我不喜欢使用GetTickCount()作为时间戳,因为它可以返回负数。尽管使用Abs()可以提供帮助,但它很笨拙并且不是最佳解决方案。

最好在.Net中使用Stopwatch或在C ++中使用QueryPerformanceCounter作为时间戳。

在C#应用程序中,我创建一个全局Stopwatch对象,启动它。稍后在应用程序中,我使用Stopwatch.ElapsedMiliseconds作为时间戳。

using System;
using System.Diagnostics;
using System.Windows.Forms;

namespace MiscApp
{
    public partial class Form1 : Form
    {
        private Stopwatch globalTimer = new Stopwatch();
        private long myStamp1 = 0;
        public Form1()
        {
            InitializeComponent();
            globalTimer.Start();
        }

        private void SomeFunction()
        {
            if (globalTimer.ElapsedMilliseconds - myStamp1 >= 3000)
            {
                myStamp1 = globalTimer.ElapsedMilliseconds;
                //Do something here...
            }
        }
    }
}