Central时区IsDaylightSavingTime夏令时触发时间异常咨询
问题分析与解决方案
你遇到的这个问题核心是未指定时区的DateTime存在时间歧义导致的,让我给你拆解清楚并给出解决办法:
为什么11/5/17 01:00:00会返回false?
在美国中部时区,2017年夏令时结束时,时钟会在11月5日凌晨2:00 CDT(夏令时,UTC-5)直接回拨到1:00 CST(标准时间,UTC-6)——也就是说,这天的凌晨1点会出现两次:
- 第一次是1:00 CDT(属于夏令时)
- 第二次是1:00 CST(属于标准时间)
你代码里创建的new DateTime(2017,11,5,1,0,0)默认是DateTimeKind.Unspecified类型,当TimeZoneInfo.IsDaylightSavingTime处理这种未指定时区的DateTime时,会默认把这个时间解析为回拨后的标准时间版本(也就是第二个1点),所以会返回false,但这并不是你预期的那个夏令时的1点。
可靠的修复方案
有两种明确的方法可以解决这个歧义问题:
方法1:使用DateTimeOffset明确时区偏移
DateTimeOffset自带时区偏移信息,完全避免时间歧义:
// 创建夏令时的1:00 CDT(对应UTC-5) var dateTimeOffset = new DateTimeOffset(2017, 11, 5, 1, 0, 0, TimeSpan.FromHours(-5)); var targetTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time"); if (targetTimeZone.IsDaylightSavingTime(dateTimeOffset)) { Console.WriteLine("Daylight Saving Time"); // 会输出预期结果 }
方法2:通过UTC时间转换避免歧义
先创建对应的UTC时间,再转换到目标时区,这样时间不会有歧义:
// 1:00 CDT 对应的UTC时间是6:00 var utcDateTime = new DateTime(2017, 11, 5, 6, 0, 0, DateTimeKind.Utc); var targetTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time"); var centralDateTime = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, targetTimeZone); if (targetTimeZone.IsDaylightSavingTime(centralDateTime)) { Console.WriteLine("Daylight Saving Time"); // 正确输出预期结果 }
如果需要处理本地系统的歧义时间,还可以先通过TimeZoneInfo.IsAmbiguousTime判断,再指定取夏令时的时间实例:
var ambiguousTime = new DateTime(2017, 11, 5, 1, 0, 0); var targetTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time"); if (targetTimeZone.IsAmbiguousTime(ambiguousTime)) { // 获取该时间点的所有可能偏移,第一个就是夏令时的偏移 var possibleOffsets = targetTimeZone.GetAmbiguousTimeOffsets(ambiguousTime); var dstOffset = possibleOffsets.First(); var dstDateTimeOffset = new DateTimeOffset(ambiguousTime, dstOffset); if (targetTimeZone.IsDaylightSavingTime(dstDateTimeOffset)) { Console.WriteLine("Daylight Saving Time"); // 符合预期输出 } }
总结
处理夏令时切换前后的时间时,一定要避免使用未指定时区的DateTime,改用DateTimeOffset或者基于UTC的时间转换,就能彻底消除时间歧义问题。
内容的提问来源于stack exchange,提问作者stackoverfloweth
相关产品推荐
相关产品推荐

