Rub*_*ink 35 .net asp.net datetime utc system.web.caching
对于实施例Cache.Add使用DateTime.Now.Add
来计算到期,即,其通过:
DateTime.Now.AddSeconds(60)
Run Code Online (Sandbox Code Playgroud)
作为absoluteExpiration
参数的值.
我认为相对计算它DateTime.UtcNow
会更正确[因为如果夏令时在现在和到期点之间的间隔开始时没有歧义].
在介绍之前DateTimeKind
,我已经猜到缓存管理中有一些丑陋的黑客攻击,如果时间不是UTC时间,它可以做一些合适的事情.
在.NET 2.0及更高版本中,我猜测它应该正确处理DateTime
计算,DateTime.UtcNow.AddSeconds(60)
因为它必须DateTime.Kind
在推理中用作输入.
多年来我一直在自信地使用它DateTime.UtcNow
作为基础,但是没有能够提出这样的理由:如果没有任何指出文档在4年多的时间里一直存在误导性,这绝对是正确的做法.
问题?
(是的,我可以仔细阅读源和/或反射器的来源,但我正在寻找一个完整的逐个打击的低点!)
Joe*_*Joe 23
我不久前在Microsoft Connect上报告了这个错误,但它已被关闭,因为无法修复.
如果您在本地时间指定绝对过期,则在.NET 2.0中仍然存在问题.
在夏令时结束的一小时内,您当地的时间不明确,因此您可能会得到意想不到的结果,即绝对到期时间可能比预期长一个小时.
在欧洲,夏令时在2009年10月25日的02:00结束.下面的示例说明如果您在01:59将一个项目放在缓存中,并在2分钟到期,它将在缓存中保留一小时2分钟.
DateTime startTime = new DateTime(2009, 10, 25, 1, 59,0);
DateTime endTime = startTime.AddMinutes(2);
// end time is two minutes after start time
DateTime startUtcTime = startTime.ToUniversalTime();
DateTime endUtcTime = endTime.ToUniversalTime();
// end UTC time is one hour and two minutes after start UTC time
Console.WriteLine("Start UTC time = " + startUtcTime.ToString());
Console.WriteLine("End UTC time = " + endUtcTime.ToString());
Run Code Online (Sandbox Code Playgroud)
.NET 2.0或更高版本的解决方法是指定Ruben指出的UTC的绝对到期时间.
微软或许应该建议在示例中使用UTC进行绝对过期,但我想有可能产生混淆,因为这个建议仅适用于.NET 2.0及更高版本.
编辑
来自评论:
但是只有在重叠期间发生转换时才会发生曝光.实际发生的单次转换是当您使用Cache.Add提交项目时
只有在夏令时结束时的一个不明确的小时内,在本地时间以AbsoluteExpiration时间插入一个项目时才会出现问题.
例如,如果您当地的时区是中欧(冬季GMT + 1,夏季GMT + 2),并且您在2009年10月25日01:59:00执行以下代码:
DateTime absoluteExpiration = DateTime.Now.AddMinutes(2);
Cache.Add(... absoluteExpiration ...)
Run Code Online (Sandbox Code Playgroud)
然后该项目将保留在缓存中一小时两分钟,而不是您通常预期的两分钟.对于一些高度时间关键的应用程序(例如股票代码,航空公司离职板),这可能是一个问题.
这里发生的是(假设欧洲时间,但任何时区的原则都是相同的):
DateTime.Now = 2009-10-25 01:59:00当地.local = GMT + 2,所以UTC = 2009-10-24 23:59:00
.AddMinutes(2)= 2009-10-25 02:01:00当地.local = GMT + 1,所以UTC = 2009-11-25 01:01:00
Cache.Add内部转换期满时间为UTC(2009-11-25 1时01分00秒),因此截止是一小时,超前于当前的UTC时间(23:59:00)两分钟.
如果使用DateTime.UtcNow代替DateTime.Now,则缓存过期将为两分钟(.NET 2.0或更高版本):
DateTime absoluteExpiration = DateTime.UtcNow.AddMinutes(2);
Cache.Add(... absoluteExpiration ...)
Run Code Online (Sandbox Code Playgroud)
来自评论:
或者我错过了什么?
不你不是.您的分析是正确的,如果您的应用程序是时间关键的并且在DST结束时的那段时间内运行,那么您使用DateTime.UtcNow是正确的.
鲁本答复中的陈述:
只要在您提供的时间设置了种类,您就可以安全使用
是不正确的.
Cache.Add
在存储之前将过期日期转换为UTC.
从Reflector(我省略了大部分参数,使其更容易阅读):
public object Add(... DateTime absoluteExpiration ...)
{
DateTime utcAbsoluteExpiration = DateTimeUtil.ConvertToUniversalTime(absoluteExpiration);
return this._cacheInternal.DoInsert(... utcAbsoluteExpiration ...);
}
Run Code Online (Sandbox Code Playgroud)
在CacheExpires.FlushExpiredItems
,utcAbsoluteExpiration
比较DateTime.UtcNow
.正如乔在他的回答中指出的那样,当缓存项的添加和到期跨越夏令时结束时,这会导致意外行为.