代码之家  ›  专栏  ›  技术社区  ›  Ruben Bartelink

缓存。添加绝对过期时间-是否基于UTC?

  •  34
  • Ruben Bartelink  · 技术社区  · 16 年前

    的示例 Cache.Add 使用 DateTime.Now.Add 要计算过期时间,即它通过:

     DateTime.Now.AddSeconds(60)
    

    作为 absoluteExpiration 参数。

    我本以为是相对于 DateTime.UtcNow 如果夏令时是从现在到到期点之间的中间时间开始的话,就没有歧义了。

    在引入 DateTimeKind 我猜在缓存管理中有一些丑陋的黑客行为,如果时间不是UTC时间,可以让它做一些适当的事情。

    在.NET 2.0及更高版本中,我猜想它应该处理 DateTime 计算为 DateTime.UtcNow.AddSeconds(60) 正确地考虑到它 DateTime.Kind 作为推论的输入。

    我一直自信地使用 日期时间.utcnow 作为多年来的基础,但未能提出一个理由,即在没有任何指示文件的情况下,这绝对是正确的做法,4年多以来一直高度误导文档。

    这些问题?

    1. 尽管暴食和谷歌搜索,我还是没能从微软那里找到任何权威性的讨论——有人能找到与此相关的东西吗?
    2. 是否有任何理由说明使用utcnow会更正确和/或更安全?

    (是的,我可以细读光源和/或反射镜的光源,但我正在寻找一个全面的吹扫降低!)

    3 回复  |  直到 11 年前
        1
  •  23
  •   to StackOverflow    11 年前

    reported this bug on Microsoft Connect 一段时间前,但它已经关闭,无法修复。

    如果在本地时间指定绝对过期时间,则.NET 2.0中仍有问题。

    在夏时制结束的一个小时内,您的本地时间不明确,因此您可能会得到意想不到的结果,即绝对到期时间可能比预期时间长一个小时。

    在欧洲,夏令时结束于2009年10月25日02:00。下面的示例说明,如果您在01:59将一个项目放置在缓存中,并且过期2分钟,那么它将在缓存中保留1小时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());
    

    .NET 2.0或更高版本的解决方法是指定ruben指出的绝对过期时间(以UTC为单位)。

    Microsoft也许应该建议在示例中使用UTC以实现绝对过期,但我想可能会出现混淆,因为此建议仅对.NET 2.0及更高版本有效。

    编辑

    从评论中:

    但只有当 转换发生在重叠期间。 实际进行的单一转换 地点是你存放物品的时候 缓存添加

    只有在夏令时结束时的一个不明确的小时内,在本地时间以绝对expiration时间将项目插入缓存中时,才会发生此问题。

    例如,如果您的本地时区是中欧(冬季为格林威治标准时间+1,夏季为格林威治标准时间+2),并且您在2009年10月25日01:59:00执行以下代码:

    DateTime absoluteExpiration = DateTime.Now.AddMinutes(2);
    Cache.Add(... absoluteExpiration ...)
    

    然后该项将在缓存中保留1小时2分钟,而不是通常预期的2分钟。对于一些时间紧迫的应用程序(如股票行情、航空公司离港公告板),这可能是一个问题。

    这里发生的是(假设是欧洲时间,但任何时区的原则都是相同的):

    • datetime.now=2009-10-25 01:59:00本地。当地时间=格林尼治标准时间+2,所以UTC=2009-10-24 23:59:00

    • .addminutes(2)=2009-10-25 02:01:00本地。本地=格林尼治标准时间+1,所以UTC=2009-11-25 01:01:00

    • cache.add在内部将过期时间转换为UTC(2009-11-25 01:01:00),使过期时间比当前的UTC时间(23:59:00)提前一小时两分钟。

    如果使用datetime.utcnow代替datetime.now,则缓存将过期两分钟(.net 2.0或更高版本):

    DateTime absoluteExpiration = DateTime.UtcNow.AddMinutes(2);
    Cache.Add(... absoluteExpiration ...)
    

    从评论中:

    还是我错过了什么?

    不,你不是。您的分析是现场分析,如果您的应用程序是时间关键型的,并且在DST结束时运行,那么您使用datetime.utcnow是正确的。

    鲁本回答中的陈述是:

    只要你提供的种类在规定的时间内就可以安全使用。

    是不正确的。

        2
  •  6
  •   Community Mohan Dere    8 年前

    Cache.Add 在存储过期日期之前将其转换为UTC。

    从Reflector(我省略了大部分参数,以便于阅读):

    public object Add(... DateTime absoluteExpiration ...)
    {
        DateTime utcAbsoluteExpiration = DateTimeUtil.ConvertToUniversalTime(absoluteExpiration);
        return this._cacheInternal.DoInsert(... utcAbsoluteExpiration ...);
    }
    

    CacheExpires.FlushExpiredItems ,请 utcAbsoluteExpiration 被比作 DateTime.UtcNow . AS Joe notes in his answer ,这会在缓存项的添加和到期跨越夏令时结束时导致意外行为。

        3
  •  3
  •   Ruben Bartelink    16 年前

    [从Jeff Sternal的回答中高度衍生出见解,我在“未完成付款”中加了1'd:d]

    似乎在1.1中(没有看到1.0,但我假设它是相似的),在没有 DateTime.Kind 并发表了一些例子 DateTime.Now -相对时间,他们感觉很舒服,立刻打电话 ToUniversalTime() 立即。

    因此…

    1. 在1.x中,如果[API用户]使用 DateTime.UtcNow (在呼叫过程中对DST有敏感度) Cache.Add )

    2. 在2.0[和3.x]中,只要 Kind 在你提供的时间是设定的[如果你从 日期时间 UtcNow ][参见Joe的评论和回答以获得充分的理由]绝对喜欢 UTCNW 作为DST切换1小时的模糊性。

    3. 这个例子保持原样,这样人们就不会对1.x工作产生误导[人们可以继续假装DST是一个古怪的边缘案例:p]。[同上,正如乔所指出的]但这是一个非常有争议的立场,因为这会导致东西在缓存中多停留一个小时。

    我仍然很感兴趣听到更多的细节,包括任何小马的细节。

    编辑:我从乔的评论中意识到我没有明确指出 使用更正确 UTCNW 如果在DST“土拨鼠小时”期间,将2.0或更高版本作为一个项目,可能会面临额外一小时缓存项目的风险。我还认为MS Doc应该指出这一事实(前提是他们需要提到这不适用于1.1[无论页面是否标记为2.0+特定]。谢谢乔。

    编辑:noda时间将有一个整洁的包装使这个万无一失:d

    推荐文章