/// <summary> /// Initializes this transition group based on the specified asjustment rule. /// </summary> /// <param name="adjustmentRule">The adjustment rule to initialize from.</param> /// <param name="standardPeriod">A reference to the pre-created standard period.</param> internal virtual void InitializeFromAdjustmentRule(TimeZoneInfo.AdjustmentRule adjustmentRule, TimeZonePeriod standardPeriod) { TimeZonePeriod daylightPeriod = new TimeZonePeriod(); // Generate an Id of the form "Daylight/2008" daylightPeriod.Id = string.Format( "{0}/{1}", TimeZonePeriod.DaylightPeriodId, adjustmentRule.DateStart.Year); daylightPeriod.Name = TimeZonePeriod.DaylightPeriodName; daylightPeriod.Bias = standardPeriod.Bias - adjustmentRule.DaylightDelta; this.timeZoneDefinition.Periods.Add(daylightPeriod.Id, daylightPeriod); this.transitionToDaylight = TimeZoneTransition.CreateTimeZoneTransition( this.timeZoneDefinition, daylightPeriod, adjustmentRule.DaylightTransitionStart); this.transitionToStandard = TimeZoneTransition.CreateTimeZoneTransition( this.timeZoneDefinition, standardPeriod, adjustmentRule.DaylightTransitionEnd); this.transitions.Add(this.transitionToDaylight); this.transitions.Add(this.transitionToStandard); }
/// <summary> /// Loads from json. /// </summary> /// <param name="jsonProperty">The json property.</param> /// <param name="service">The service.</param> internal override void LoadFromJson(JsonObject jsonProperty, ExchangeService service) { base.LoadFromJson(jsonProperty, service); foreach (string key in jsonProperty.Keys) { switch (key) { case XmlAttributeNames.Id: this.id = jsonProperty.ReadAsString(key); break; case XmlElementNames.Transition: foreach (object uncastJsonTransition in jsonProperty.ReadAsArray(key)) { JsonObject jsonTransition = uncastJsonTransition as JsonObject; TimeZoneTransition transition = TimeZoneTransition.Create(this.timeZoneDefinition, jsonTransition.ReadTypeString()); transition.LoadFromJson(jsonTransition, service); this.transitions.Add(transition); } break; } } }
/// <summary> /// Initializes this transition group based on the specified asjustment rule. /// </summary> /// <param name="adjustmentRule">The adjustment rule to initialize from.</param> /// <param name="standardPeriod">A reference to the pre-created standard period.</param> internal virtual void InitializeFromAdjustmentRule(TimeZoneInfo.AdjustmentRule adjustmentRule, TimeZonePeriod standardPeriod) { if (adjustmentRule.DaylightDelta.TotalSeconds == 0) { // If the time zone info doesn't support Daylight Saving Time, we just need to // create one transition to one group with one transition to the standard period. TimeZonePeriod standardPeriodToSet = new TimeZonePeriod(); standardPeriodToSet.Id = string.Format( "{0}/{1}", standardPeriod.Id, adjustmentRule.DateStart.Year); standardPeriodToSet.Name = standardPeriod.Name; standardPeriodToSet.Bias = standardPeriod.Bias; // this.timeZoneDefinition.Periods.Add(standardPeriodToSet.Id, standardPeriodToSet); this.timeZoneDefinition.Periods[standardPeriodToSet.Id] = standardPeriodToSet; this.transitionToStandard = new TimeZoneTransition(this.timeZoneDefinition, standardPeriodToSet); this.transitions.Add(this.transitionToStandard); } else { TimeZonePeriod daylightPeriod = new TimeZonePeriod(); // Generate an Id of the form "Daylight/2008" daylightPeriod.Id = string.Format( "{0}/{1}", TimeZonePeriod.DaylightPeriodId, adjustmentRule.DateStart.Year); daylightPeriod.Name = TimeZonePeriod.DaylightPeriodName; daylightPeriod.Bias = standardPeriod.Bias - adjustmentRule.DaylightDelta; // this.timeZoneDefinition.Periods.Add(daylightPeriod.Id, daylightPeriod); this.timeZoneDefinition.Periods[daylightPeriod.Id] = daylightPeriod; this.transitionToDaylight = TimeZoneTransition.CreateTimeZoneTransition( this.timeZoneDefinition, daylightPeriod, adjustmentRule.DaylightTransitionStart); TimeZonePeriod standardPeriodToSet = new TimeZonePeriod(); standardPeriodToSet.Id = string.Format( "{0}/{1}", standardPeriod.Id, adjustmentRule.DateStart.Year); standardPeriodToSet.Name = standardPeriod.Name; standardPeriodToSet.Bias = standardPeriod.Bias; // this.timeZoneDefinition.Periods.Add(standardPeriodToSet.Id, standardPeriodToSet); this.timeZoneDefinition.Periods[standardPeriodToSet.Id] = standardPeriodToSet; this.transitionToStandard = TimeZoneTransition.CreateTimeZoneTransition( this.timeZoneDefinition, standardPeriodToSet, adjustmentRule.DaylightTransitionEnd); this.transitions.Add(this.transitionToDaylight); this.transitions.Add(this.transitionToStandard); } }
/// <summary> /// Tries to read element from XML. /// </summary> /// <param name="reader">The reader.</param> /// <returns>True if element was read.</returns> internal override bool TryReadElementFromXml(EwsServiceXmlReader reader) { switch (reader.LocalName) { case XmlElementNames.Periods: do { reader.Read(); if (reader.IsStartElement(XmlNamespace.Types, XmlElementNames.Period)) { TimeZonePeriod period = new TimeZonePeriod(); period.LoadFromXml(reader); this.periods.Add(period.Id, period); } }while (!reader.IsEndElement(XmlNamespace.Types, XmlElementNames.Periods)); return(true); case XmlElementNames.TransitionsGroups: do { reader.Read(); if (reader.IsStartElement(XmlNamespace.Types, XmlElementNames.TransitionsGroup)) { TimeZoneTransitionGroup transitionGroup = new TimeZoneTransitionGroup(this); transitionGroup.LoadFromXml(reader); this.transitionGroups.Add(transitionGroup.Id, transitionGroup); } }while (!reader.IsEndElement(XmlNamespace.Types, XmlElementNames.TransitionsGroups)); return(true); case XmlElementNames.Transitions: do { reader.Read(); if (reader.IsStartElement()) { TimeZoneTransition transition = TimeZoneTransition.Create(this, reader.LocalName); transition.LoadFromXml(reader); this.transitions.Add(transition); } }while (!reader.IsEndElement(XmlNamespace.Types, XmlElementNames.Transitions)); return(true); default: return(false); } }
/// <summary> /// Adds a transition group with a single transition to the specified period. /// </summary> /// <param name="timeZonePeriod">The time zone period.</param> /// <returns>A TimeZoneTransitionGroup.</returns> private TimeZoneTransitionGroup CreateTransitionGroupToPeriod(TimeZonePeriod timeZonePeriod) { TimeZoneTransition transitionToPeriod = new TimeZoneTransition(this, timeZonePeriod); TimeZoneTransitionGroup transitionGroup = new TimeZoneTransitionGroup(this, this.transitionGroups.Count.ToString()); transitionGroup.Transitions.Add(transitionToPeriod); this.transitionGroups.Add(transitionGroup.Id, transitionGroup); return(transitionGroup); }
/// <summary> /// Tries to read element from XML. /// </summary> /// <param name="reader">The reader.</param> /// <returns>True if element was read.</returns> internal override bool TryReadElementFromXml(EwsServiceXmlReader reader) { reader.EnsureCurrentNodeIsStartElement(); TimeZoneTransition transition = TimeZoneTransition.Create(this.timeZoneDefinition, reader.LocalName); transition.LoadFromXml(reader); EwsUtilities.Assert( transition.TargetPeriod != null, "TimeZoneTransitionGroup.TryReadElementFromXml", "The transition's target period is null."); this.transitions.Add(transition); return(true); }
/// <summary> /// Compares the transitions. /// </summary> /// <param name="x">The first transition.</param> /// <param name="y">The second transition.</param> /// <returns>A negative number if x is less than y, 0 if x and y are equal, a positive number if x is greater than y.</returns> private int CompareTransitions(TimeZoneTransition x, TimeZoneTransition y) { if (x == y) { return(0); } else if (x.GetType() == typeof(TimeZoneTransition)) { return(-1); } else if (y.GetType() == typeof(TimeZoneTransition)) { return(1); } else { AbsoluteDateTransition firstTransition = (AbsoluteDateTransition)x; AbsoluteDateTransition secondTransition = (AbsoluteDateTransition)y; return(DateTime.Compare(firstTransition.DateTime, secondTransition.DateTime)); } }
/// <summary> /// Compares the transitions. /// </summary> /// <param name="x">The first transition.</param> /// <param name="y">The second transition.</param> /// <returns>A negative number if x is less than y, 0 if x and y are equal, a positive number if x is greater than y.</returns> private int CompareTransitions(TimeZoneTransition x, TimeZoneTransition y) { if (x == y) { return 0; } else if (x.GetType() == typeof(TimeZoneTransition)) { return -1; } else if (y.GetType() == typeof(TimeZoneTransition)) { return 1; } else { AbsoluteDateTransition firstTransition = (AbsoluteDateTransition)x; AbsoluteDateTransition secondTransition = (AbsoluteDateTransition)y; return DateTime.Compare(firstTransition.DateTime, secondTransition.DateTime); } }
/// <summary> /// Initializes the private members holding references to the transitions to the Daylight /// and Standard periods. /// </summary> private void InitializeTransitions() { if (this.transitionToStandard == null) { foreach (TimeZoneTransition transition in this.transitions) { if (transition.TargetPeriod.IsStandardPeriod || (this.transitions.Count == 1)) { this.transitionToStandard = transition; } else { this.transitionToDaylight = transition; } } } // If we didn't find a Standard period, this is an invalid time zone group. if (this.transitionToStandard == null) { throw new ServiceLocalException(Strings.InvalidOrUnsupportedTimeZoneDefinition); } }
/// <summary> /// Loads from json. /// </summary> /// <param name="jsonProperty">The json property.</param> /// <param name="service">The service.</param> internal override void LoadFromJson(JsonObject jsonProperty, ExchangeService service) { base.LoadFromJson(jsonProperty, service); foreach (string key in jsonProperty.Keys) { switch (key) { case XmlAttributeNames.Name: this.name = jsonProperty.ReadAsString(key); break; case XmlAttributeNames.Id: this.id = jsonProperty.ReadAsString(key); break; case XmlElementNames.Periods: foreach (object jsonPeriod in jsonProperty.ReadAsArray(key)) { TimeZonePeriod period = new TimeZonePeriod(); period.LoadFromJson(jsonPeriod as JsonObject, service); // OM:1648848 Bad timezone data from clients can include duplicate rules // for one year, with duplicate ID. In that case, let the first one win. if (!this.periods.ContainsKey(period.Id)) { this.periods.Add(period.Id, period); } else { service.TraceMessage( TraceFlags.EwsTimeZones, string.Format( "An entry with the same key (Id) '{0}' already exists in Periods. Cannot add another one. Existing entry: [Name='{1}', Bias='{2}']. Entry to skip: [Name='{3}', Bias='{4}'].", period.Id, this.Periods[period.Id].Name, this.Periods[period.Id].Bias, period.Name, period.Bias)); } } break; case XmlElementNames.TransitionsGroups: foreach (object arrayOfTransitionsTypeInstance in jsonProperty.ReadAsArray(key)) { TimeZoneTransitionGroup transitionGroup = new TimeZoneTransitionGroup(this); transitionGroup.LoadFromJson(arrayOfTransitionsTypeInstance as JsonObject, service); this.transitionGroups.Add(transitionGroup.Id, transitionGroup); } break; case XmlElementNames.Transitions: JsonObject arrayOfTransitionsType = jsonProperty.ReadAsJsonObject(key); foreach (object uncastJsonTransition in arrayOfTransitionsType.ReadAsArray(XmlElementNames.Transition)) { JsonObject jsonTransition = uncastJsonTransition as JsonObject; TimeZoneTransition transition = TimeZoneTransition.Create(this, jsonTransition.ReadTypeString()); transition.LoadFromJson(jsonTransition, service); this.transitions.Add(transition); } break; default: break; } } // EWS can return a TimeZone definition with no Id. Generate a new Id in this case. if (string.IsNullOrEmpty(this.id)) { string nameValue = string.IsNullOrEmpty(this.Name) ? string.Empty : this.Name; this.Id = NoIdPrefix + Math.Abs(nameValue.GetHashCode()).ToString(); } this.transitions.Sort(this.CompareTransitions); }
/// <summary> /// Initializes a new instance of the <see cref="TimeZoneDefinition"/> class. /// </summary> /// <param name="timeZoneInfo">The time zone info used to initialize this definition.</param> internal TimeZoneDefinition(TimeZoneInfo timeZoneInfo) : this() { this.Id = timeZoneInfo.Id; this.Name = timeZoneInfo.DisplayName; // TimeZoneInfo only supports one standard period, which bias is the time zone's base // offset to UTC. TimeZonePeriod standardPeriod = new TimeZonePeriod(); standardPeriod.Id = TimeZonePeriod.StandardPeriodId; standardPeriod.Name = TimeZonePeriod.StandardPeriodName; standardPeriod.Bias = -timeZoneInfo.BaseUtcOffset; TimeZoneInfo.AdjustmentRule[] adjustmentRules = timeZoneInfo.GetAdjustmentRules(); TimeZoneTransition transitionToStandardPeriod = new TimeZoneTransition(this, standardPeriod); if (adjustmentRules.Length == 0) { this.periods.Add(standardPeriod.Id, standardPeriod); // If the time zone info doesn't support Daylight Saving Time, we just need to // create one transition to one group with one transition to the standard period. TimeZoneTransitionGroup transitionGroup = new TimeZoneTransitionGroup(this, "0"); transitionGroup.Transitions.Add(transitionToStandardPeriod); this.transitionGroups.Add(transitionGroup.Id, transitionGroup); TimeZoneTransition initialTransition = new TimeZoneTransition(this, transitionGroup); this.transitions.Add(initialTransition); } else { for (int i = 0; i < adjustmentRules.Length; i++) { TimeZoneTransitionGroup transitionGroup = new TimeZoneTransitionGroup(this, this.transitionGroups.Count.ToString()); transitionGroup.InitializeFromAdjustmentRule(adjustmentRules[i], standardPeriod); this.transitionGroups.Add(transitionGroup.Id, transitionGroup); TimeZoneTransition transition; if (i == 0) { // If the first adjustment rule's start date in not undefined (DateTime.MinValue) // we need to add a dummy group with a single, simple transition to the Standard // period and a group containing the transitions mapping to the adjustment rule. if (adjustmentRules[i].DateStart > DateTime.MinValue.Date) { TimeZoneTransition transitionToDummyGroup = new TimeZoneTransition( this, this.CreateTransitionGroupToPeriod(standardPeriod)); this.transitions.Add(transitionToDummyGroup); AbsoluteDateTransition absoluteDateTransition = new AbsoluteDateTransition(this, transitionGroup); absoluteDateTransition.DateTime = adjustmentRules[i].DateStart; transition = absoluteDateTransition; this.periods.Add(standardPeriod.Id, standardPeriod); } else { transition = new TimeZoneTransition(this, transitionGroup); } } else { AbsoluteDateTransition absoluteDateTransition = new AbsoluteDateTransition(this, transitionGroup); absoluteDateTransition.DateTime = adjustmentRules[i].DateStart; transition = absoluteDateTransition; } this.transitions.Add(transition); } // If the last adjustment rule's end date is not undefined (DateTime.MaxValue), // we need to create another absolute date transition that occurs the date after // the last rule's end date. We target this additional transition to a group that // contains a single simple transition to the Standard period. DateTime lastAdjustmentRuleEndDate = adjustmentRules[adjustmentRules.Length - 1].DateEnd; if (lastAdjustmentRuleEndDate < DateTime.MaxValue.Date) { AbsoluteDateTransition transitionToDummyGroup = new AbsoluteDateTransition( this, this.CreateTransitionGroupToPeriod(standardPeriod)); transitionToDummyGroup.DateTime = lastAdjustmentRuleEndDate.AddDays(1); this.transitions.Add(transitionToDummyGroup); } } }
/// <summary> /// Adds a transition group with a single transition to the specified period. /// </summary> /// <param name="timeZonePeriod">The time zone period.</param> /// <returns>A TimeZoneTransitionGroup.</returns> private TimeZoneTransitionGroup CreateTransitionGroupToPeriod(TimeZonePeriod timeZonePeriod) { TimeZoneTransition transitionToPeriod = new TimeZoneTransition(this, timeZonePeriod); TimeZoneTransitionGroup transitionGroup = new TimeZoneTransitionGroup(this, this.transitionGroups.Count.ToString()); transitionGroup.Transitions.Add(transitionToPeriod); this.transitionGroups.Add(transitionGroup.Id, transitionGroup); return transitionGroup; }
/// <summary> /// Tries to read element from XML. /// </summary> /// <param name="reader">The reader.</param> /// <returns>True if element was read.</returns> internal override bool TryReadElementFromXml(EwsServiceXmlReader reader) { switch (reader.LocalName) { case XmlElementNames.Periods: do { reader.Read(); if (reader.IsStartElement(XmlNamespace.Types, XmlElementNames.Period)) { TimeZonePeriod period = new TimeZonePeriod(); period.LoadFromXml(reader); // OM:1648848 Bad timezone data from clients can include duplicate rules // for one year, with duplicate ID. In that case, let the first one win. if (!this.periods.ContainsKey(period.Id)) { this.periods.Add(period.Id, period); } else { reader.Service.TraceMessage( TraceFlags.EwsTimeZones, string.Format( "An entry with the same key (Id) '{0}' already exists in Periods. Cannot add another one. Existing entry: [Name='{1}', Bias='{2}']. Entry to skip: [Name='{3}', Bias='{4}'].", period.Id, this.Periods[period.Id].Name, this.Periods[period.Id].Bias, period.Name, period.Bias)); } } }while (!reader.IsEndElement(XmlNamespace.Types, XmlElementNames.Periods)); return(true); case XmlElementNames.TransitionsGroups: do { reader.Read(); if (reader.IsStartElement(XmlNamespace.Types, XmlElementNames.TransitionsGroup)) { TimeZoneTransitionGroup transitionGroup = new TimeZoneTransitionGroup(this); transitionGroup.LoadFromXml(reader); this.transitionGroups.Add(transitionGroup.Id, transitionGroup); } }while (!reader.IsEndElement(XmlNamespace.Types, XmlElementNames.TransitionsGroups)); return(true); case XmlElementNames.Transitions: do { reader.Read(); if (reader.IsStartElement()) { TimeZoneTransition transition = TimeZoneTransition.Create(this, reader.LocalName); transition.LoadFromXml(reader); this.transitions.Add(transition); } }while (!reader.IsEndElement(XmlNamespace.Types, XmlElementNames.Transitions)); return(true); default: return(false); } }
/// <summary> /// Initializes a new instance of the <see cref="TimeZoneDefinition"/> class. /// </summary> /// <param name="timeZoneInfo">The time zone info used to initialize this definition.</param> internal TimeZoneDefinition(TimeZoneInfo timeZoneInfo) : this() { this.Id = timeZoneInfo.Id; this.Name = timeZoneInfo.DisplayName; // TimeZoneInfo only supports one standard period, which bias is the time zone's base // offset to UTC. TimeZonePeriod standardPeriod = new TimeZonePeriod(); standardPeriod.Id = TimeZonePeriod.StandardPeriodId; standardPeriod.Name = TimeZonePeriod.StandardPeriodName; standardPeriod.Bias = -timeZoneInfo.BaseUtcOffset; this.periods.Add(standardPeriod.Id, standardPeriod); TimeZoneInfo.AdjustmentRule[] adjustmentRules = timeZoneInfo.GetAdjustmentRules(); TimeZoneTransition transitionToStandardPeriod = new TimeZoneTransition(this, standardPeriod); if (adjustmentRules.Length == 0) { // If the time zone info doesn't support Daylight Saving Time, we just need to // create one transition to one group with one transition to the standard period. TimeZoneTransitionGroup transitionGroup = new TimeZoneTransitionGroup(this, "0"); transitionGroup.Transitions.Add(transitionToStandardPeriod); this.transitionGroups.Add(transitionGroup.Id, transitionGroup); TimeZoneTransition initialTransition = new TimeZoneTransition(this, transitionGroup); this.transitions.Add(initialTransition); } else { for (int i = 0; i < adjustmentRules.Length; i++) { TimeZoneTransitionGroup transitionGroup = new TimeZoneTransitionGroup(this, this.transitionGroups.Count.ToString()); transitionGroup.InitializeFromAdjustmentRule(adjustmentRules[i], standardPeriod); this.transitionGroups.Add(transitionGroup.Id, transitionGroup); TimeZoneTransition transition; if (i == 0) { // If the first adjustment rule's start date in not undefined (DateTime.MinValue) // we need to add a dummy group with a single, simple transition to the Standard // period and a group containing the transitions mapping to the adjustment rule. if (adjustmentRules[i].DateStart > DateTime.MinValue.Date) { TimeZoneTransition transitionToDummyGroup = new TimeZoneTransition( this, this.CreateTransitionGroupToPeriod(standardPeriod)); this.transitions.Add(transitionToDummyGroup); AbsoluteDateTransition absoluteDateTransition = new AbsoluteDateTransition(this, transitionGroup); absoluteDateTransition.DateTime = adjustmentRules[i].DateStart; transition = absoluteDateTransition; } else { transition = new TimeZoneTransition(this, transitionGroup); } } else { AbsoluteDateTransition absoluteDateTransition = new AbsoluteDateTransition(this, transitionGroup); absoluteDateTransition.DateTime = adjustmentRules[i].DateStart; transition = absoluteDateTransition; } this.transitions.Add(transition); } // If the last adjustment rule's end date is not undefined (DateTime.MaxValue), // we need to create another absolute date transition that occurs the date after // the last rule's end date. We target this additional transition to a group that // contains a single simple transition to the Standard period. DateTime lastAdjustmentRuleEndDate = adjustmentRules[adjustmentRules.Length - 1].DateEnd; if (lastAdjustmentRuleEndDate < DateTime.MaxValue.Date) { AbsoluteDateTransition transitionToDummyGroup = new AbsoluteDateTransition( this, this.CreateTransitionGroupToPeriod(standardPeriod)); transitionToDummyGroup.DateTime = lastAdjustmentRuleEndDate.AddDays(1); this.transitions.Add(transitionToDummyGroup); } } }
/// <summary> /// Initializes this transition group based on the specified asjustment rule. /// </summary> /// <param name="adjustmentRule">The adjustment rule to initialize from.</param> /// <param name="standardPeriod">A reference to the pre-created standard period.</param> internal virtual void InitializeFromAdjustmentRule(TimeZoneInfo.AdjustmentRule adjustmentRule, TimeZonePeriod standardPeriod) { TimeZonePeriod daylightPeriod = new TimeZonePeriod(); // Generate an Id of the form "Daylight/2008" daylightPeriod.Id = string.Format( "{0}/{1}", TimeZonePeriod.DaylightPeriodId, adjustmentRule.DateStart.Year); daylightPeriod.Name = TimeZonePeriod.DaylightPeriodName; daylightPeriod.Bias = standardPeriod.Bias - adjustmentRule.DaylightDelta; this.timeZoneDefinition.Periods.Add(daylightPeriod.Id, daylightPeriod); this.transitionToDaylight = TimeZoneTransition.CreateTimeZoneTransition( this.timeZoneDefinition, daylightPeriod, adjustmentRule.DaylightTransitionStart); TimeZonePeriod standardPeriodToSet = new TimeZonePeriod(); standardPeriodToSet.Id = string.Format( "{0}/{1}", standardPeriod.Id, adjustmentRule.DateStart.Year); standardPeriodToSet.Name = standardPeriod.Name; standardPeriodToSet.Bias = standardPeriod.Bias; this.timeZoneDefinition.Periods.Add(standardPeriodToSet.Id, standardPeriodToSet); this.transitionToStandard = TimeZoneTransition.CreateTimeZoneTransition( this.timeZoneDefinition, standardPeriodToSet, adjustmentRule.DaylightTransitionEnd); this.transitions.Add(this.transitionToDaylight); this.transitions.Add(this.transitionToStandard); }
/// <summary> /// Loads from json. /// </summary> /// <param name="jsonProperty">The json property.</param> /// <param name="service">The service.</param> internal override void LoadFromJson(JsonObject jsonProperty, ExchangeService service) { base.LoadFromJson(jsonProperty, service); foreach (string key in jsonProperty.Keys) { switch (key) { case XmlAttributeNames.Name: this.name = jsonProperty.ReadAsString(key); break; case XmlAttributeNames.Id: this.id = jsonProperty.ReadAsString(key); break; case XmlElementNames.Periods: foreach (object jsonPeriod in jsonProperty.ReadAsArray(key)) { TimeZonePeriod period = new TimeZonePeriod(); period.LoadFromJson(jsonPeriod as JsonObject, service); this.periods.Add(period.Id, period); } break; case XmlElementNames.TransitionsGroups: foreach (object arrayOfTransitionsTypeInstance in jsonProperty.ReadAsArray(key)) { TimeZoneTransitionGroup transitionGroup = new TimeZoneTransitionGroup(this); transitionGroup.LoadFromJson(arrayOfTransitionsTypeInstance as JsonObject, service); this.transitionGroups.Add(transitionGroup.Id, transitionGroup); } break; case XmlElementNames.Transitions: JsonObject arrayOfTransitionsType = jsonProperty.ReadAsJsonObject(key); foreach (object uncastJsonTransition in arrayOfTransitionsType.ReadAsArray(XmlElementNames.Transition)) { JsonObject jsonTransition = uncastJsonTransition as JsonObject; TimeZoneTransition transition = TimeZoneTransition.Create(this, jsonTransition.ReadTypeString()); transition.LoadFromJson(jsonTransition, service); this.transitions.Add(transition); } break; default: break; } } // EWS can return a TimeZone definition with no Id. Generate a new Id in this case. if (string.IsNullOrEmpty(this.id)) { string nameValue = string.IsNullOrEmpty(this.Name) ? string.Empty : this.Name; this.Id = NoIdPrefix + Math.Abs(nameValue.GetHashCode()).ToString(); } this.transitions.Sort(this.CompareTransitions); }