请注意:本页内容发布于 2276 天前,内容可能已经过时,请注意甄别。
天行有常,不为尧存,不为桀亡。
原文链接:https://blogs.msdn.microsoft.com/oldnewthing/20031024-00/?p=42053
Welcome Knowledge Base article 932955 readers! Remember, the information on this Web site is not official Microsoft documentation. Daylight Savings Time ends this weekend in most of North America and Europe, so it seems a good time to discuss the whole problem of Daylight Savings Time and timestamps.
欢迎来自KB932955的朋友们!请记住,本博客上的信息并非微软官方文档。这个周末,夏令时在北美多数地区及欧洲即将结束,借此机会,我们来讨论一下夏令时和时间戳之间那些不可不说的故事。
A common complaint is that all the time zone conversion functions like FileTimeToLocalFileTime apply the current Daylight Savings Time (DST) bias rather than the bias that was in effect at the time in question.
常见的争论之一是,所有有关时区转换的方法——例如FileTimeToLocalFileTime,会将当前的夏令时偏差应用于转换中,而不是当前有效的时间偏差。
For example, suppose you have a FILETIME structure that represents “1 January 2000 12:00AM”. If you are in Redmond during the summertime, this converts to “31 December 1999 5:00PM”, seven hours difference, even though the time difference between Redmond and UTC was eight hours at that time. (I.e., when people in London were celebrating the new year, it was 4pm in Redmond, not 5pm.)
例如,你有一个FILETIME结构,其值为『2000年1月1日 12:00AM』。如果你在夏天时的Redmond,那么转换结果将是『1999年12月31日 5:00PM』,二者间有7小时的时差,尽管Redmond所在的时区跟UTC之间实际有8小时的时差。(换句话说,当伦敦的人们庆祝新年时,Redmond的时间是下午4点,而不是下午5点。)
The reason is that the time got converted from “1 January 2000 12:00AM UTC” to “31 December 1999 5:00PM PDT“. So, technically, the conversion is correct. Of course, nobody was using PDT on December 31, 1999 in Redmond; everybody was on PST.
发生这种情况的原因是上述时间从『2000年1月1日 12:00AM UTC』转换为了『1999年12月31日 5:00PM PDT(太平洋夏季时间,此时启用夏令时)』,从技术的角度来说,转换结果是正确的,尽管1999年12月31日的时候,没有在Redmond的人会用PDT时间,大家都在用PST(太平洋标准时间)。
Why don’t the time zone conversion functions use the time zone appropriate for the time of year?
为什么时区转换相关的方法不能用符合当时时间的时区进行转换操作呢?
One reason is that it means that FileTimeToLocalFileTime and LocalFileTimeToFileTime would no longer be inverses of each other. If you had a local time during the “limbo hour” during the cutover from standard time to daylight time, it would have no corresponding UTC time because there was no such thing as 2:30am local time. (The clock jumped from 2am to 3am.) Similarly, a local time of 2:30am during the cutover from daylight time back to standard time would have two corresponding UTC times.
原因之一是,如此一来 FileTimeToLocalFileTime 和 LocalFileTimeToFileTime 将不再互为逆操作。如果要转换的本地时间正好处于标准时间和夏令时切换的『间隙』中,那么对应的UTC时间就不存在了,因为此时不存在2:30AM这样的本地时间(此时时钟直接从早晨2点跳到了早晨3点)。类似的,从夏令时切换回本地时间的2:30AM将有2个对应的UTC时间。
Another reason is that the laws regarding daylight savings time are in constant flux. For example, if the year in the example above was 1977 instead of 2000, the conversion would have been correct because the United States was running on year-round Daylight Savings Time due to the energy crisis. Of course, this information isn’t encoded anywhere in the TIME_ZONE_INFORMATION structure. Similarly, during World War 2, the United States went on DST all year round. And between 1945 and 1966, the DST rules varied from region to region.
另一个原因是有关夏令时的律法在不断变化。例如,如果前面所说的例子发生在1977年而不是2000年,那么转换结果就是正确的,因为当时由于能源危机,美国正在实行全年的夏令时制度,显然,这样的信息是不会出现在TIME_ZONE_INFORMATION结构中的任何一处的。类似的情况还有二战时美国整年整年都在实行夏时制,还有1945年到1966年不同地区实行的不同的夏时制规则等等。
DST rules are in flux even today. The DST cutover dates in Israel are decided on a year-by-year basis by the Knesset. As a result, there is no deterministic formula for the day, and therefore no way to know it ahead of time.
夏时制规则直到今天也仍旧在变动。以色列的夏令时起止日期由议会年复一年地决定,故而没有确定的公式可以计算这个起止时间,也没有办法预知这个起止时间。
(Warning: .NET content ahead; two days in a row, what’s gotten into me!?)
(警告:前方有.NET内容出没;一下子来两个日子,我到底是怎么回事!?)
Compare the output of FileInfo.LastWriteTime.ToString(“f”) with what you see in the property sheet for a file that was last written to on the other side of the DST transition. For example, suppose the file was last modified on October 17, during DST but DST is not currently in effect. Explorer’s file properties reports Thursday, October 17, 2003, 8:45:38 AM, but .NETs FileInfo reports Thursday, October 17, 2003, 9:45 AM.
尝试比较一下针对在夏令时启用前后、你在文件的属性对话框中看到的两个最后修改时间,与对其使用 FileInfo.LastWriteTime.ToString(“f”) 的输出。例如,某文件最后修改日期为10月17日,这个日期是夏令时的时候记录的,但眼下并不是夏令时时期。资源管理器会显示该文件的最后修改日期为『2003年10月18日星期四 8:45:38AM』,但.NET的FileInfo将返回『2003年10月17日星期四 9:45AM』。
En gang til for prins Knud: Win32 does not attempt to guess which time zone rules were in effect at that other time. So Win32 says, “Thursday, October 17, 2002 8:45:38 AM PST”. Note: Pacific Standard Time. Even though October 17 was during Pacific Daylight Time, Win32 displays the time as standard time because that’s what time it is now.
En gang til for prins Knud(译注:这是啥玩意儿……):Win32不会去猜测保存这个日期时采用的时区,所以直接报告『2002年10月17日星期四 8:45:38 AM PST』。请注意:是PST。即使10月17日仍在太平洋夏季时间期间,Win32仍会将该最后修改时间显示为PST,因为眼下就是PST。
.NET says, “Well, if the rules in effect now were also in effect on October 17, 2003, then that would be daylight time” so it displays “Thursday, October 17, 2003, 9:45 AM PDT” – daylight time.
.NET则会觉得,『好吧,如果现在执行的夏令时规则在2003年10月17日时也有效,那么那应该是个夏令时时间』,所以回报『2003年10月17日星期四 9:45AM PDT』——夏令时时间。
So .NET gives a value which is more intuitively correct, but is also potentially incorrect, and which is not invertible. Win32 gives a value which is intuitively incorrect, but is strictly correct.
所以这样算下来,.NET给出的值是最符合直觉的,但也很可能是不正确的,这也是不可逆的。Win32给出的结果可能是违反直觉的额,但一定是最正确的。
I suspect that the .NET behavior was for compatibility with Visual Basic, but I don’t know for sure.
我估计.NET这样的设计可能是为了考虑Visual Basic兼容性,不过我不太确定。
远嚣 Comment