如何通过时区ID获取夏令时起止日期?C#技术问询
获取指定时区的夏令时起止日期(不受服务器时区影响)
嘿,你已经用TimeZoneInfo.IsDaylightSavingTime搞定了夏令时判断,接下来要拿起止日期其实很简单——不过得先避开一个坑:TimeZone.GetDaylightChanges是绑定服务器本地时区的,不能直接用它来拿"GMT Standard Time"的规则。正确的姿势是用TimeZoneInfo自带的调整规则(AdjustmentRule),它能直接针对你指定的时区提取夏令时切换时间,完全不受服务器所在时区干扰。
核心思路
- 通过
TimeZoneInfo.GetAdjustmentRules()获取目标时区的所有夏令时规则(毕竟不同年份的规则可能会变) - 根据目标日期的年份,匹配对应的调整规则
- 解析规则里的
TransitionTime属性,得到夏令时的开始/结束日期(这些时间都是目标时区的本地时间)
修改后的完整代码
using System; public class Program { public static void Main() { var myDate = new DateTime(2020, 5, 31, 11, 9, 0); var myTimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time"); bool isDaylightSavingTime = myTimeZoneInfo.IsDaylightSavingTime(myDate); Console.WriteLine(isDaylightSavingTime); if (isDaylightSavingTime) { // 获取该时区的所有夏令时调整规则 var adjustmentRules = myTimeZoneInfo.GetAdjustmentRules(); int targetYear = myDate.Year; AdjustmentRule matchedRule = null; // 找到目标年份对应的规则(规则是按日期范围划分的) foreach (var rule in adjustmentRules) { if (rule.DateStart.Year <= targetYear && rule.DateEnd.Year >= targetYear) { matchedRule = rule; break; } } if (matchedRule != null) { // 解析夏令时开始/结束的具体日期 DateTime dstStart = GetTransitionDateTime(targetYear, matchedRule.DaylightTransitionStart, myTimeZoneInfo); DateTime dstEnd = GetTransitionDateTime(targetYear, matchedRule.DaylightTransitionEnd, myTimeZoneInfo); Console.WriteLine($"夏令时开始:{dstStart:yyyy-MM-dd HH:mm:ss} (GMT时区本地时间)"); Console.WriteLine($"夏令时结束:{dstEnd:yyyy-MM-dd HH:mm:ss} (GMT时区本地时间)"); // 如果需要转UTC,直接用下面的代码 // DateTime dstStartUtc = TimeZoneInfo.ConvertTimeToUtc(dstStart, myTimeZoneInfo); // DateTime dstEndUtc = TimeZoneInfo.ConvertTimeToUtc(dstEnd, myTimeZoneInfo); } else { Console.WriteLine($"年份{targetYear}没有对应的夏令时调整规则"); } } } // 辅助方法:把TransitionTime转换成具体的DateTime private static DateTime GetTransitionDateTime(int year, TransitionTime transition, TimeZoneInfo timeZone) { // 处理固定日期规则(比如每年3月25日) if (transition.IsFixedDateRule) { return new DateTime(year, transition.Month, transition.Day, transition.TimeOfDay.Hour, transition.TimeOfDay.Minute, transition.TimeOfDay.Second); } // 处理相对日期规则(比如三月最后一个星期日) else { DateTime firstDayOfMonth = new DateTime(year, transition.Month, 1); // 计算当月第一个目标星期几的日期 int daysToFirstTarget = ((int)transition.DayOfWeek - (int)firstDayOfMonth.DayOfWeek + 7) % 7; DateTime targetDay = firstDayOfMonth.AddDays(daysToFirstTarget); // 如果是"最后一个"星期几,就往后推到当月最后一个符合条件的日期 if (transition.Week == 5) { while (targetDay.AddDays(7).Month == transition.Month) { targetDay = targetDay.AddDays(7); } } // 否则取第N个星期几 else { targetDay = targetDay.AddDays((transition.Week - 1) * 7); } return targetDay.Add(transition.TimeOfDay); } } }
关键细节说明
AdjustmentRule是按日期范围存储的,所以要先匹配目标年份对应的规则TransitionTime分两种类型:固定日期和相对日期(比如"某月最后一个星期日"),辅助方法已经帮你处理了这两种情况- 得到的起止日期是目标时区的本地时间,如果需要转换成UTC,直接用
TimeZoneInfo.ConvertTimeToUtc()即可
内容的提问来源于stack exchange,提问作者Femil Shajin
相关产品推荐
相关产品推荐

