同一时区同一时间下IsDaylightSavingTime方法返回值不一致问题
问题分析与解决方案
这个问题的核心是DateTime的Kind属性不一致,导致TimeZoneInfo.IsDaylightSavingTime方法对"同一时间"的解析逻辑完全不同,最终返回了不同的结果。
为什么会出现这个差异?
首先得明确TimeZoneInfo.IsDaylightSavingTime(DateTime)的行为规则:
- 当传入的
DateTime的Kind是Unspecified(你用new DateTime(2018, 3, 10, 22, 0, 0)创建的对象就是这个类型):方法会直接把这个时间当成目标时区(Pacific Standard Time)的本地时间来判断是否处于夏令时。 - 当传入的
DateTime的Kind是Local或Utc:方法会先把这个时间转换为目标时区的时间,再做夏令时判断。
而从FileTime转换回来的DateTime,默认是Local类型(因为DateTime.FromFileTime()返回的是系统本地时区的时间)。如果你的系统本地时区不是Pacific Standard Time,这个转换过程就会把"看起来相同的时间字符串"转换成目标时区里完全不同的实际时间,自然会得到不同的夏令时判断结果。
举个具体的例子:
假设你的系统时区是Eastern Standard Time:
- 你创建的
reminderstarttime是Unspecified的2018-03-10 22:00,方法把它当成Pacific时区的时间——此时Pacific时区还没进入夏令时(2018年Pacific夏令时切换是3月11日凌晨2点,拨快到3点),所以返回false。 - 从
FileTime转回来的DateTime是Local的2018-03-10 22:00(Eastern时区),方法先把它转成UTC时间2018-03-11 02:00,再转成Pacific时区的2018-03-11 06:00——此时Pacific已经进入夏令时了,所以返回true。
怎么解决这个问题?
这里有几个可靠的方案:
1. 明确指定DateTime的Kind并统一转换逻辑
创建DateTime时,明确把它标记为目标时区的本地时间,或者统一转换为UTC后再处理:
var tzInfo = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"); // 明确创建Unspecified的时间 var reminderstarttime = new DateTime(2018, 3, 10, 22, 0, 0, DateTimeKind.Unspecified); var isRemDstWithNormal = tzInfo.IsDaylightSavingTime(reminderstarttime); // 如果是从FileTime获取的时间,先转换为UTC,再转成目标时区的时间 var fileTime = reminderstarttime.ToFileTime(); var fromFileTimeUtc = DateTime.FromFileTimeUtc(fileTime); var convertedTime = TimeZoneInfo.ConvertTimeFromUtc(fromFileTimeUtc, tzInfo); var isRefDstWithFile = tzInfo.IsDaylightSavingTime(convertedTime);
2. 使用DateTimeOffset代替DateTime(最推荐)
DateTimeOffset本身包含了时间和时区偏移量,完全避免了Kind属性带来的歧义,是处理时区相关逻辑的首选类型:
var tzInfo = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"); var reminderstarttime = new DateTime(2018, 3, 10, 22, 0, 0); var reminderOffset = new DateTimeOffset(reminderstarttime, tzInfo.GetUtcOffset(reminderstarttime)); var referencetimeOffset = reminderOffset.AddHours(10); var isRemDst = tzInfo.IsDaylightSavingTime(reminderOffset); var isRefDst = tzInfo.IsDaylightSavingTime(referencetimeOffset);
3. 统一将所有时间转换为目标时区的本地时间
不管原始时间的Kind是什么,先把它转换为目标时区的时间,再做判断:
var tzInfo = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"); var reminderstarttime = new DateTime(2018, 3, 10, 22, 0, 0); // 转换为目标时区的时间 var pacificReminderTime = TimeZoneInfo.ConvertTime(reminderstarttime, tzInfo); var isRemDst = tzInfo.IsDaylightSavingTime(pacificReminderTime); // 从FileTime获取的时间也做同样转换 var fileTime = reminderstarttime.ToFileTime(); var fromFileTime = DateTime.FromFileTime(fileTime); var pacificFromFileTime = TimeZoneInfo.ConvertTime(fromFileTime, tzInfo); var isRefDstFromFile = tzInfo.IsDaylightSavingTime(pacificFromFileTime);
这样就能保证所有时间都按照目标时区的规则来判断夏令时,不会出现结果不一致的情况了。
内容的提问来源于stack exchange,提问作者Bala Sravan Dindukurthi
相关产品推荐
相关产品推荐

