public static TimeZoneStructure FromTimeZoneInfo(TimeZoneInfo staticTimeZone) { TimeZoneInfo.AdjustmentRule[] rules = staticTimeZone.GetAdjustmentRules(); if (rules.Length > 1) { throw new ArgumentException("Cannot create TimeZoneStructure from a time zone with multiple DST rules"); } TimeZoneStructure structure = new TimeZoneStructure(); if (rules.Length == 0) { // no daylight saving structure.SetBias(staticTimeZone.BaseUtcOffset, new TimeSpan()); structure.stStandardDate = new SystemTime(); structure.stDaylightDate = new SystemTime(); } else { TimeZoneInfo.AdjustmentRule rule = rules[0]; structure.SetBias(staticTimeZone.BaseUtcOffset, rule.DaylightDelta); structure.stStandardDate = AdjustmentRuleHelper.GetStandardDate(rule); structure.stDaylightDate = AdjustmentRuleHelper.GetDaylightDate(rule); } return(structure); }
/// Note about how Outlook selects the effective adjustment rule: /// For backward compatibility reasons, the effective rule is always the static timezone /// rule used by the OS. /// It's possible however that there is no dynamic rule that matches the static rule, /// If that's the case, Outlook will replace the dynamic rule of the current year /// with the static rule, which will be marked as the effective rule. /// <param name="effectiveRule">null if there are no daylight savings</param> public static TimeZoneDefinitionStructure FromTimeZoneInfo(TimeZoneInfo timezone, TimeZoneInfo.AdjustmentRule effectiveRule, int effectiveRuleYear, bool isRecurringTimeZoneRule) { TimeZoneInfo.AdjustmentRule[] adjustmentRules = timezone.GetAdjustmentRules(); if (effectiveRule != null) { if ((effectiveRule.DaylightTransitionStart.IsFixedDateRule || effectiveRule.DaylightTransitionEnd.IsFixedDateRule) && effectiveRule.DateStart.Year < effectiveRule.DateEnd.Year) { // a rule can either be fixed-date (wYear is not zero) or floating-date (wYear is zero) // a fixed-date rule cannot span multiple years. throw new NotImplementedException("Effective DST rule cannot be fixed-date and span multiple years"); } if (adjustmentRules.Length == 0) { // effective rule != null means timezone rule is defined, but the timezone has no such rule throw new ArgumentException("Time zone does not match effective rule"); } } TimeZoneRuleFlags effectiveRuleFlags = TimeZoneRuleFlags.EffectiveTimeZoneRule; if (isRecurringTimeZoneRule) { effectiveRuleFlags |= TimeZoneRuleFlags.RecurringTimeZoneRule; } TimeZoneRuleStructure[] tzRules; if (adjustmentRules.Length == 0) { // at this point effectiveRule must be null TimeZoneRuleStructure ruleStructure = new TimeZoneRuleStructure(); ruleStructure.SetBias(timezone.BaseUtcOffset, new TimeSpan()); ruleStructure.wYear = 1601; // That's what Outlook 2007 SP3 uses ruleStructure.TZRuleFlags = effectiveRuleFlags; tzRules = new TimeZoneRuleStructure[] { ruleStructure }; } else { List <TimeZoneRuleStructure> rules = new List <TimeZoneRuleStructure>(); // First we will create a list of the dynamic rules: // we have an effective rule and at least one dynamic rule int firstRuleYear = adjustmentRules[0].DateStart.Year; if (firstRuleYear > 1) { TimeZoneRuleStructure firstRule = new TimeZoneRuleStructure(); firstRule.SetBias(timezone.BaseUtcOffset, adjustmentRules[0].DaylightDelta); firstRule.wYear = (ushort)(firstRuleYear - 1); rules.Add(firstRule); } for (int index = 0; index < adjustmentRules.Length; index++) { TimeZoneInfo.AdjustmentRule adjustmentRule = adjustmentRules[index]; TimeZoneRuleStructure rule = new TimeZoneRuleStructure(); rule.wYear = (ushort)adjustmentRule.DateStart.Year;; rule.SetBias(timezone.BaseUtcOffset, adjustmentRule.DaylightDelta); rule.stStandardDate = AdjustmentRuleHelper.GetStandardDate(adjustmentRule); rule.stDaylightDate = AdjustmentRuleHelper.GetDaylightDate(adjustmentRule); rules.Add(rule); } int lastRuleYear = adjustmentRules[adjustmentRules.Length - 1].DateEnd.Year; if (lastRuleYear < 9999) { TimeZoneRuleStructure lastRule = new TimeZoneRuleStructure(); lastRule.SetBias(timezone.BaseUtcOffset, adjustmentRules[adjustmentRules.Length - 1].DaylightDelta); lastRule.wYear = (ushort)(lastRuleYear + 1); rules.Add(lastRule); } // Outlook will try to find a rule that match the static rule, and will use the last rule that fits // now we will replace a dynamic rule with the appropriate static rule // find the index for the rule int effectiveRuleIndex = 0; for (int index = 0; index < rules.Count; index++) { if (effectiveRuleYear >= rules[index].wYear) { effectiveRuleIndex = index; } } // prepare the effective rule structure TimeZoneRuleStructure ruleStructure = new TimeZoneRuleStructure(); ruleStructure.wYear = rules[effectiveRuleIndex].wYear; ruleStructure.TZRuleFlags = effectiveRuleFlags; if (effectiveRule == null) { // We should have a no-daylight-savings rule ruleStructure.SetBias(timezone.BaseUtcOffset, new TimeSpan()); } else { ruleStructure.SetBias(timezone.BaseUtcOffset, effectiveRule.DaylightDelta); ruleStructure.stStandardDate = AdjustmentRuleHelper.GetStandardDate(effectiveRule); ruleStructure.stDaylightDate = AdjustmentRuleHelper.GetDaylightDate(effectiveRule); } rules[effectiveRuleIndex] = ruleStructure; tzRules = rules.ToArray(); } TimeZoneDefinitionStructure structure = new TimeZoneDefinitionStructure(); structure.KeyName = timezone.Id; structure.TZRules = tzRules; return(structure); }