返璞归真:夏令时错误再次通过SetLastModified出现

No matter how well you know a topic, or a codebase, it's never to late (or early) to get nailed by a latest bug a over a half-decade old.

无论您对某个主题或代码库的了解程度如何,都不会为时已晚(或早)被一个超过十年的老错误所困扰。

DasBlog, the ASP.NET 2 blog engine that powers this blog, is done. It's not dead, but it's done. It's very stable. We had some commits last year, and I committed a bug fix in February, but it's really well understood and very baked. My blog hasn't been down for traffic spike reasons in literally years as DasBlog scales nicely on a single machine.

DasBlog (为该博客提供动力的ASP.NET 2博客引擎)已完成。 它还没有死,但是已经完成了。 非常稳定去年我们进行了一些提交,而我在2月提交了一个错误修复程序,但是它的确很容易理解并且非常成熟。 实际上,由于DasBlog可以在一台计算机上很好地扩展,多年来我的博客并没有因为流量激增的原因而关闭。

It was 10:51pm PDT (that's Pacific Daylight Time) and I was writing a blog post about the clocks in my house, given that PST (that's Pacific Standard Time) was switching over soon. I wrote it up in Windows Live Writer, posted it to my blog, then hit Hanselman.com to check it out.

现在是太平洋标准时间(太平洋夏令时间)晚上10:51,鉴于PST(太平洋标准时间)即将切换,我正在写一篇有关我家时钟的博客文章。 我用Windows Live Writer编写了它,然后将其发布到我的博客中,然后单击Hanselman.com进行检查。

Bam. 404.

am 404。

What? 404? Nonsense. Refresh.

什么? 404? 废话。 刷新。

404.

404。

*heart in chest* Have I been hacked? What's going on? OK, to the logs!

*胸中的心*我被黑了吗? 这是怎么回事? OK,到日志!

l2    time    2011-11-06T05:36:31    code    1    message    Error:System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: utcDate
at System.Web.HttpCacnhePolicy.UtcSetLastModified(DateTime utcDate)
at System.Web.HttpCachePolicy.SetLastModified(DateTime date)
at newtelligence.DasBlog.Web.Core.SiteUtilities.GetStatusNotModified(DateTime latest) in C:\dev\DasBlog\source\newtelligence.DasBlog.Web.Core\SiteUtilities.cs:line 1253
at newtelligence.DasBlog.Web.Core.SharedBasePage.NotModified(EntryCollection entryCollection) in C:\dev\DasBlog\source\newtelligence.DasBlog.Web.Core\SharedBasePage.cs:line 1182
at newtelligence.DasBlog.Web.Core.SharedBasePage.Page_Load(Object sender, EventArgs e) in C:\dev\DasBlog\source\newtelligence.DasBlog.Web.Core\SharedBasePage.cs:line 1213
at System.EventHandler.Invoke(Object sender, EventArgs e)
at System.Web.UI.Control.OnLoad(EventArgs e)
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) while processing http://www.hanselman.com/blog/default.aspx.

What's going on? Out of range? What's out of range. Ok, my site is down for the first time in years. I must have messed it up with my clock post. I'll delete that. OK, delete. Whew.

这是怎么回事? 超出范围? 什么超出范围。 好的,我的网站多年来第一次关闭。 我一定把钟表弄糟了。 我将其删除。 确定,删除。 ew。

Refresh.

刷新。

404.

404。

WHAT?!?

什么?!?

Logs, same error, now the file is a meg and growing, as this messages is happening of hundreds of times a minute. OK, to the code!

日志,同样的错误,现在该文件变得越来越庞大,因为该消息每分钟发生数百次。 OK,给代码!

UtcSetLastModified is used for setting cache-specific HTTP headers and for controlling the ASP.NET page output cache. It lets me tell HTTP that something hasn't been modified since a certain time. I've got a utility that figures out which post was the last modified or most recently had comments modified, then I tell the home page, then the browser, so everyone can decide if there is fresh content or not.

UtcSetLastModified用于设置特定于缓存的HTTP标头和用于控制ASP.NET页面输出缓存。 它让我告诉HTTP,自某些时间以来没有进行过任何修改。 我有一个实用程序,可以确定哪个帖子是最后修改的,或者最近修改过的评论,然后我告诉主页,然后是浏览器,这样每个人都可以决定是否有新内容。

public DateTime GetLatestModifedEntryDateTime(IBlogDataService dataService, EntryCollection entries)
{
//figure out if send a 304 Not Modified or not...
return latest //the lastTime anything interesting happened.
}

In the BasePage we ask ourselves, can we avoid work and give a 304?

在BasePage中,我们问自己,我们可以避免工作并且给304吗?

//Can we get away with an "if-not-modified" header?
if (SiteUtilities.GetStatusNotModified(SiteUtilities.GetLatestModifedEntryDateTime(dataService, entryCollection)))
{
//snip
}

However, note that I'm have to call SetLastModified though. Seems that UtcSetLastModified is private. (Why?) When I call SetLastModified it does this:

但是,请注意,我必须调用SetLastModified 。 似乎UtcSetLastModified是私有的。 (为什么?)当我调用SetLastModified时,它会这样做:

public void SetLastModified(DateTime date)
{
DateTime utcDate = DateTimeUtil.ConvertToUniversalTime(date);
this.UtcSetLastModified(utcDate);
}

Um, OK. Lame. So that means I have to work in local time. I retrieve dates and convert them ToLocalTime().

嗯好瘸。 因此,这意味着我必须在当地时间工作。 我检索日期并将其转换为ToLocalTime ()。

At this point, you might say, Oh, I get it, he's called ToLocalTime() too many times and double converted his times. That's what I thought. However, after .NET 2 that is possible.

此时,您可能会说,哦,我明白了,他被称为ToLocalTime()的次数太多了,并且转换了两倍的时间。 我也那么认为。 但是,在.NET 2之后,这是可能的

The value returned by the conversion is a DateTime whose Kind property always returns Local. Consequently, a valid result is returned even if ToLocalTime is applied repeatedly to the same DateTime.

转换返回的值是DateTime,Kind属性始终返回Local。 因此,即使将ToLocalTime重复应用于同一DateTime,也将返回有效结果

But. We originally wrote DasBlog in .NET 1.1 first and MOVED it to .NET 2 some years later. I suspect that I'm actually counting on some incorrect behavior deep in own our (Clemens Vasters and mine) TimeZone and Data Access code that worked with that latent incorrect behavior (overconverting DateTimes to local time) and now that's not happening. And hasn't been happening for four years.

但。 我们最初最初是在.NET 1.1中编写DasBlog的,然后在几年后将其移动到.NET 2 。 我怀疑我实际上是在深深地依靠我们自己的(Clemens Vasters和我的)TimeZone和数据访问代码中的一些错误行为来处理这种潜在的错误行为(将DateTimes过度转换为本地时间),但是现在这没有发生。 而且已经四年没有发生了。

Hopefully you can see where this is going.

希望您能看到进展。

It seems a comment came in around 5:36am GMT or 10:36pm PDT which is 1:36am EST. That become the new Last Modified Date. At some point we an hour was added in conversion as PDT wasn't PST yet but EDT was EST.

似乎在格林尼治标准时间上午5:36或太平洋夏令时间10:36 pm (美国东部标准时间1:36)左右发表了评论。 成为新的上次修改日期。 在某个时候,由于PDT还不是PST,但EDT是EST,所以转换时间增加了一个小时。

Your brain exploded yet? Hate Daylight Saving Time? Ya, me too.

你的大脑爆炸了吗? 讨厌夏时制吗? 是的,我也是。

Anyway, that DateTime became 2:36am EST rather than 1:36am. Problem is, 2:36am EST is/was the future as 6:46 GMT hadn't happened yet.

无论如何,该DateTime变成了美国东部时间凌晨2:36,而不是凌晨1:36。 问题是,美国东部标准时间2:36 am是/是将来,因为格林尼治标准时间6:46尚未发生。

A sloppy 5 year old bug that has been happening for an hour each year that was likely always there but counted on 10 year old framework code that was fixed 7 years ago. Got Unit Tests for DST? I don't.

每年发生一个小时的一个草率5年错误,该错误很可能一直存在,但是依靠的是7年前已修复的10年框架代码。 获得DST的单元测试? 我不。

My server is in the future, but actually not as far in the future as it usually is. My server in on the East Coast and it was 1:51am. However, the reasons my posts sometimes look like they are from the future, is I store everything in the neutral UTC/GMT zone, so it was 5:51am the next day on my file system.

我的服务器在将来,但实际上不像往常那样远。 我的服务器在美国东海岸,是凌晨1:51。 但是,我的帖子有时看起来像是将来的原因是我将所有内容存储在中立的UTC / GMT区域中,因此第二天凌晨5:51在我的文件系统上。

Moral of the story?

这个故事所讲的道德?

I need to confirm that my server is on GMT time and that none of my storage code is affected my Daylight Saving Time.

我需要确认我的服务器处于格林尼治标准时间(GMT),并且我的所有存储代码都不会影响我的夏令时。

Phrased differently, don't use DateTime.Now for ANY date calculations or to store anything. Use DateTime.UTCNow and be aware that some methods will freak out if you send them future dates, as they should. Avoid doing ANYTHING in local time until that last second when you show the DateTime to the user.

措辞不同,请不要将DateTime.Now用于任何日期计算或存储任何内容。 使用DateTime.UTCNow并请注意,如果您将某些方法发送给以后的日期,它们将变得有些奇怪。 避免在本地时间执行任何操作,直到向用户显示DateTime的最后一秒为止。

In my case, in the nine minutes it took to debug this, it resolved itself. The future became the present and the future last modified DateTime became valid. Is there a bug? There sure it, at least, there is for an hour, once a year. Now the real question is, do I fix it and possibly break something that works the other 8759 hours in a year. Hm, that IS still four 9's of uptime. (Ya, I know I need to fix it.)

以我为例,在花了九分钟进行调试后,它自己解决了。 将来成为现在,将来最后修改的DateTime变为有效。 是否有错误? 确保至少每年有一个小时,一次。 现在真正的问题是,我是否要解决此问题,并可能会破坏一年中其他8759小时可用的功能。 嗯,那仍然是四个9的正常运行时间。 (是的,我知道我需要修复它。)

"My code has no bugs, it runs exactly as it was written." - Some famous programmer

“我的代码没有错误,它完全按照编写的方式运行。” -一些著名的程序员

Until next year. ;)

直到明年。 ;)

翻译自: https://www.hanselman.com/blog/back-to-basics-daylight-savings-time-bugs-strike-again-with-setlastmodified

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值