我刚注意到我们的一个单元测试花了十秒钟。在玩完它之后,我创建了一个最小的linqpad示例来重现它:
void Main()
{
Stopwatch sw = new Stopwatch();
sw.Start();
var timeZone = TimeZoneInfo.Local;
for(int i=0; i<10000; i++)
{
//var dateTime = TimeZoneInfo.ConvertTime(DateTime.UtcNow, timeZone);
var dateTime = TimeZoneInfo.ConvertTime(DateTime.MinValue, timeZone);
}
sw.Stop();
(sw.ElapsedMilliseconds + " ms").Dump();
}
我的电脑或构建电脑需要40秒。如果我使用DateTime.UtcNow,则需要15毫秒。
为什么有这样的原因或解决方法?
编辑:正如评论中所建议的那样,我反编译TimeZoneInfo并且在DateTime.MinValue上有一个特例:
static public DateTime ConvertTime(DateTime dateTime, TimeZoneInfo destinationTimeZone) {
// Special case to give a way clearing the cache without exposing ClearCachedData()
if (dateTime.Ticks == 0) {
ClearCachedData();
}
看起来(test?)代码在每次使用DateTime.MinValue调用时清除缓存。
提出为什么会发生这种情况的问题。
答案 0 :(得分:3)
没有必要反编译。您可以在the .NET Framework Reference Source或the CoreCLR source code on GitHub中找到此内容。
.NET 4.6中添加了一个特殊情况作为非官方的解决方法,用于清除当时没有公开ClearCachedData
方法的WinRT等环境中的时区缓存。 I describe this further here
偶尔清除时区缓存通常不会产生明显的影响。由于环路紧张,你会看到它。如果这是您的用例的问题,那么我建议使用ConvertTimeFromUtc
方法或与ConvertTime
一起使用的DateTimeOffset
版本。那些代码路径没有达到特殊情况。
是的,我同意这应该记录得更好。我会看看能不能搞定。
请注意,从逻辑上讲,转换DateTime.MinValue
的时区并没有多大意义,因为我们今天所知的时区在第1年并不存在。