将TimeSpan.TotalMilliseconds转换为长整型

4
我有一些 DateTime 变量,想要使用 System.Threading.Timer 等待直到这个时间到来。如果时间已过,我希望计时器立即启动。 问题是 TimeSpan.TotalMillisecondsdouble 类型,而计时器的最大到期时间类型是 long
我尝试使用以下代码将到期时间最大化为 long.MaxValue
DateTime someUtcTime;
// Max due time to long.MaxValue
double doubleDueTime = Math.Min(
    (double)long.MaxValue,
    someUtcTime.Subtract(DateTime.UtcNow).TotalMilliseconds);

// Avoid negative numbers
long dueTime = Math.Max(0L, (long)doubleDueTime);

_timer.Change(dueTime, System.Threading.Timeout.Infinite);

但是事实证明,将 long.MaxValue 强制转换为双精度浮点数再转回长整型会得到一个负数(在未经检查的代码中)。请发送代码。
编辑:显然,无论你使用哪个Timer.Change重载,它们都受限于4294967294 (UInt32.MaxValue - 1) 毫秒。

解决方案:

覆盖两个极端情况(someUtcTime = DateTime.MaxValue; UtcNow = DateTime.MinValue; 和反之亦然)。

const uint MAX_SUPPORTED_TIMEOUT = uint.MaxValue - 1; //0xfffffffe

DateTime someUtcTime;
double doubleDueTime = (someUtcTime - DateTime.UtcNow).TotalMilliseconds;

// Avoid negative numbers
doubleDueTime = Math.Max(0d, doubleDueTime);

// Max due time to uint.MaxValue - 1
uint dueTime = (uint)Math.Min(MAX_SUPPORTED_TIMEOUT, doubleDueTime);

你的代码中 Math.Min((double)long.MaxValue 的目的是什么? - Gabe
1
请给我发送代码。希望这是个玩笑! - Mitch Wheat
@Gabe:日期太遥远了? - Mitch Wheat
@Mitch, 这似乎只是一个简单的两分钟任务,但我却搞不定。挫败感促使我产生幽默感。这是一种说法:“我的学者同伴们,你们会如何解决这个难题?” 我希望 SO 并不完全禁止幽默 :) - HuBeZa
你担心未来三亿年的时间戳吗? - Gabe
4个回答

4
自从 (DateTime.MaxValue - DateTime.MinValue).TotalMilliseconds 是315537897600000,而long.MaxValue是9223372036854775807(long 可以表示比任何两个DateTime值之间的最大毫秒数大4个数量级的值),因此您永远不会有一个时间太远的问题。
这就足够了:
DateTime someUtcTime;
// Max due time to long.MaxValue
double doubleDueTime = (someUtcTime - DateTime.UtcNow).TotalMilliseconds;

// Avoid negative numbers
long dueTime = Math.Max(0L, (long)doubleDueTime);

_timer.Change(dueTime, System.Threading.Timeout.Infinite);

1
不错的观点,伙计。虽然我进行了编辑,但限制是UInt32.MaxValue - 1,所以它可以在未来约50天内工作。我将使用这个加上@Marino的建议。 - HuBeZa

4
也许只需使用Ticks属性(Ticks为Long类型),并乘以TimeSpan.TicksPerMillisecond常量(每毫秒10,000个ticks)即可。

1
听起来像是可行的,但对我来说在真实世界中使用引号标记表示时间并不自然。也许只有我这样。 - HuBeZa

2
Timespan timespan = someUtcTime.Subtract(DateTime.UtcNow);
long time = timespan.TotalMilliseconds <= long.MaxValue ? (long)timespan.TotalMilliseconds : -1;

if (time == -1) {
 sorry.nocando();
}
else {
 just.doit();
}

顺便说一下:如果你使用很长的毫秒数,你可以得到292471208年的时间跨度,我不认为你的代码会被使用那么久。有可能太阳已经扩张到超过火星,地球也不存在了:D


请注意,我假设时间是正向的进展,霍金认为时间甚至可能是虚构的,或者倒退,因此“-1”可能是一个可能的时间数量 :) - Marino Šimić

0
计时器旨在等待一定时间间隔(通常小于24小时)。
您的预期用途是什么?调度程序通常会有一个事件/任务列表,并且每隔一分钟(也许每秒钟)周期性地检查是否需要触发任何任务。
也许像Quartz.Net这样的东西可能比较合适?

这是一种调度程序,但它的功能非常简单,我不想将其与第三方库耦合。 - HuBeZa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接