我正在C#程序中捕获一些事件,这些事件以时间戳作为系统tickcount(自开始时间以来的毫秒数)返回。
根据我看过的其他问题,知道我可以从System.Environment.TickCount
属性(或其他东西)获得相同的数字,如何推断出与我收到的TickCount相对应的DateTime对象? / p>
答案 0 :(得分:6)
如果没有更多信息,你就不可能(即便如此,它也可能含糊不清)。 Environment.TickCount
返回:
一个32位有符号整数,包含自上次启动计算机以来经过的时间量(以毫秒为单位)。
...除非你能从某个地方找到计算机启动的时间,否则你运气不好。您可以使用注册表项或系统调用来查找上次启动时间,但我不了解它们。当然,您可以尽可能快地在Environment.TickCount
和DateTime.UtcNow
之后(或之前)获得近似值,并找出两者之间的差异:< / p>
public static DateTime UnreliableDateTimeFromTickCount(int tickCount)
{
DateTime now = DateTime.UtcNow;
DateTime boot = now - TimeSpan.FromMilliseconds(Environment.TickCount);
return boot + TimeSpan.FromMilliseconds(tickCount);
}
然而,即使 with ,该值也会每24.9天循环一次,因此如果计算机已经打开的时间超过了这个值,那么计数就不明确了。
我建议尽可能避免使用Environment.TickCount
,基本上 - 这完全在你的控制之下吗?
答案 1 :(得分:2)
我知道这是一个非常老的问题,但是由于这是我搜索时Google的第一个热门产品,因此我认为其他人可能会来到这里。 @JonSkeet答案中的所有要点都是有效的,请务必阅读它们并充分理解它适用于您的位置。对于我的具体情况,我知道我需要转换的滴答计数值将在最近几天之内,但是存在捕获的值是在TickCount溢出之前进行转换的风险。下面是我编写的方法,该方法应该处理TickCount溢出的情况,并将给定的滴答计数转换为DateTime,只要它在过去49天内即可。
详细介绍Environment.TickCount的工作方式:打开计算机后,它从0开始,每毫秒递增。在启动24.9天后,达到了Int32的容量,并且TickCount从Int32.MaxValue转换为Int32.MinValue。初始换行后,它将每49.7天继续溢出。
/// <summary>
/// Converts the given tick count into a DateTime. Since TickCount rolls over after 24.9 days,
/// then every 49.7 days, it is assumed that the given tickCount occurrs in the past and is
/// within the last 49.7 days.
/// </summary>
/// <param name="tickCount">A tick count that has occurred in the past 49.7 days</param>
/// <returns>The DateTime the given tick count occurred</returns>
private DateTime ConvertTickToDateTime(int tickCount)
{
// Get a reference point for the current time
int nowTick = Environment.TickCount;
DateTime currTime = DateTime.Now;
Int64 mSecElapsed = 0;
// Check for overflow condition
if( tickCount < nowTick) // Then no overflow has occurred since the recorded tick
{
// MIN|--------------TC---------------0------------Now-------------|MAX
mSecElapsed = nowTick - tickCount;
}
else // tickCount >= currTick; Some overflow has occurred since the recorded tick
{
// MIN|--------------Now---------------0------------TC-------------|MAX
mSecElapsed = Convert.ToInt64((int.MaxValue - tickCount) + (nowTick + Math.Abs(Convert.ToDouble(int.MinValue)))); // Time BEFORE overflow + time since the overflow
}
DateTime tickCountAsDateTime = currTime - TimeSpan.FromMilliseconds(mSecElapsed);
return tickCountAsDateTime;
}
为了测试该方法,我使用了以下代码:
static void Main(string[] args)
{
Console.WriteLine("Test Start Time: {0}", DateTime.Now);
// 10 seconds ago
int tc0 = CalculateTC(TimeSpan.FromSeconds(10));
Console.WriteLine("Expect 10 seconds ago: {0}", ConvertTickToDateTime(tc0));
// 10 minutes ago
int tc1 = CalculateTC(TimeSpan.FromMinutes(10));
Console.WriteLine("Expect 10 minutes ago: {0}", ConvertTickToDateTime(tc1));
// 10 hours ago
int tc2 = CalculateTC(TimeSpan.FromHours(10));
Console.WriteLine("Expect 10 hours ago: {0}", ConvertTickToDateTime(tc2));
// 1 Day ago
int tc3 = CalculateTC(TimeSpan.FromDays(1));
Console.WriteLine("Expect 1 Day ago: {0}", ConvertTickToDateTime(tc3));
// 10 Day ago
int tc4 = CalculateTC(TimeSpan.FromDays(10));
Console.WriteLine("Expect 10 Days ago: {0}", ConvertTickToDateTime(tc4));
// 30 Day ago
int tc5 = CalculateTC(TimeSpan.FromDays(30));
Console.WriteLine("Expect 30 Days ago: {0}", ConvertTickToDateTime(tc5));
// 48 Day ago
int tc6 = CalculateTC(TimeSpan.FromDays(48));
Console.WriteLine("Expect 48 Days ago: {0}", ConvertTickToDateTime(tc6));
// 50 Day ago (Should read as a more recent time because of the Environment.TickCount wrapping limit - within a day or two)
int tc7 = CalculateTC(TimeSpan.FromDays(50));
Console.WriteLine("Expect to not see 50 Days ago: {0}", ConvertTickToDateTime(tc7));
// 10 Seconds ahead (Should read as a very old date - around 50 days ago)
int tc8 = Convert.ToInt32(Environment.TickCount + TimeSpan.FromSeconds(10).TotalMilliseconds);
Console.WriteLine("Expect to not see 10 seconds from now: {0}", ConvertTickToDateTime(tc8));
}
private static int CalculateTC(TimeSpan timespan)
{
int nowTick = Environment.TickCount;
double mSecToGoBack = timespan.TotalMilliseconds;
int tc;
if (Math.Abs(nowTick - int.MinValue) >= mSecToGoBack) // Then we don't have to deal with an overflow
{
tc = Convert.ToInt32(nowTick - mSecToGoBack);
}
else // Deal with the overflow wrapping
{
double remainingTime = nowTick + Math.Abs(Convert.ToDouble(int.MinValue));
remainingTime = mSecToGoBack - remainingTime;
tc = Convert.ToInt32(int.MaxValue - remainingTime);
}
return tc;
}
以下是测试应用程序的输出:
Test Start Time: 5/3/2019 4:30:05 PM
Expect 10 seconds ago: 5/3/2019 4:29:55 PM
Expect 10 minutes ago: 5/3/2019 4:20:05 PM
Expect 10 hours ago: 5/3/2019 6:30:05 AM
Expect 1 Day ago: 5/2/2019 4:30:05 PM
Expect 10 Days ago: 4/23/2019 4:30:05 PM
Expect 30 Days ago: 4/3/2019 4:30:05 PM
Expect 48 Days ago: 3/16/2019 4:30:05 PM
Expect to not see 50 Days ago: 5/3/2019 9:32:53 AM
Expect to not see 10 seconds from now: 3/14/2019 11:27:28 PM
我希望这对可能与我处于类似状况的人有所帮助。
答案 2 :(得分:1)
不是滴答计数为// Set up the network to use HttpURLConnection as the HTTP client.
Network network = new BasicNetwork(new HurlStack());
// Instantiate the RequestQueue with the cache and network.
requestQueue = new RequestQueue(cache, network);
// Start the queue
requestQueue.start();
似乎您希望使用不同的数据类型:
int
TimeSpan
(但是,根据您所提问题的措辞,我不确定100%)
下面是一个使用Windows Management Instrumentation获取这些属性的代码示例。
DateTime
答案 3 :(得分:0)
我似乎从杰伦的解决方案中得到了错误的结果;这可能是个错误/不正确-涉及到溢出的复杂性,但这使我接近测试的正确结果,试图近似结果:
// TimeSpan result
var approxUpTime = TryApproximateUpTime();
private static TimeSpan? TryApproximateUpTime()
{
TimeSpan? retVal;
var envTickCountInMs =
Environment.TickCount;
try
{
retVal =
envTickCountInMs > 0
?
new DateTime()
.AddMilliseconds(Environment.TickCount) -
DateTime.MinValue
:
new TimeSpan(
new DateTime(
((long)int.MaxValue + (envTickCountInMs & int.MaxValue)) * 10 * 1000).Ticks);
}
catch (Exception)
{
// IGNORE
retVal = null;
}
return retVal;
}