/// <summary> /// Evaluates the specified reference date. /// </summary> /// <param name="referenceDate">The reference date.</param> /// <param name="periodStart">The period start.</param> /// <param name="periodEnd">The period end.</param> /// <param name="includeReferenceDateInResults"> /// if set to <c>true</c> [include reference date in results]. /// </param> /// <returns></returns> public override ISet <IPeriod> Evaluate(IDateTime referenceDate, DateTime periodStart, DateTime periodEnd, bool includeReferenceDateInResults) { // Ensure the reference date is associated with the time zone if (referenceDate.AssociatedObject == null) { referenceDate.AssociatedObject = TimeZone; } var infos = new List <ITimeZoneInfo>(TimeZone.TimeZoneInfos); // Evaluate extra time periods, without re-evaluating ones that were already evaluated if ((EvaluationStartBounds == DateTime.MaxValue && EvaluationEndBounds == DateTime.MinValue) || (periodEnd.Equals(EvaluationStartBounds)) || (periodStart.Equals(EvaluationEndBounds))) { foreach (ITimeZoneInfo curr in infos) { var evaluator = curr.GetService(typeof(IEvaluator)) as IEvaluator; Debug.Assert(curr.Start != null, "TimeZoneInfo.Start must not be null."); Debug.Assert(curr.Start.TzId == null, "TimeZoneInfo.Start must not have a time zone reference."); Debug.Assert(evaluator != null, "TimeZoneInfo.GetService(typeof(IEvaluator)) must not be null."); // Time zones must include an effective start date/time // and must provide an evaluator. // Set the start bounds if (EvaluationStartBounds > periodStart) { EvaluationStartBounds = periodStart; } // FIXME: 5 years is an arbitrary number, to eliminate the need // to recalculate time zone information as much as possible. DateTime offsetEnd = periodEnd.AddYears(5); // Adjust our reference date to never fall out of bounds with // the time zone information IDateTime tziReferenceDate = referenceDate; if (tziReferenceDate.LessThan(curr.Start)) { tziReferenceDate = curr.Start; } // Determine the UTC occurrences of the Time Zone observances ISet <IPeriod> periods = evaluator.Evaluate( tziReferenceDate, periodStart, offsetEnd, includeReferenceDateInResults); foreach (IPeriod period in periods) { Periods.Add(period); var o = new Occurrence(curr, period); _occurancesLookup.Add(o); } if (EvaluationEndBounds == DateTime.MinValue || EvaluationEndBounds < offsetEnd) { EvaluationEndBounds = offsetEnd; } } ProcessOccurrences(referenceDate); } else { if (EvaluationEndBounds != DateTime.MinValue && periodEnd > EvaluationEndBounds) { Evaluate(referenceDate, EvaluationEndBounds, periodEnd, includeReferenceDateInResults); } } return(Periods); }