/// <summary>Gets the previous date.</summary> /// <param name="dateTime">The date time.</param> /// <param name="fp">The frequency pattern.</param> /// <returns></returns> private static DateTime GetPreviousDate(DateTime dateTime, IFrequencyPattern fp) { fp.DisableBusinessRules(); #region Set FrequencyPatternType FrequencyPatternType fpType; if (!Enum.TryParse(fp.PatternType, out fpType)) { Logger.Log(LogSeverity.Warning, string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", "ScheduleManager", Environment.NewLine, "GetNextDate"), "Error parsing FrequencyPattern, fpType"); } DailyPatternVariant fpDailyPatternVariant; if (Enum.TryParse(fp.DailyPatternOption, out fpDailyPatternVariant)) { Logger.Log(LogSeverity.Warning, string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", "ScheduleManager", Environment.NewLine, "GetNextDate"), "Error parsing FrequencyPattern, fpDailyPatternVariant"); } MonthlyPatternVariant fpMonthlyPatternVariant; if (Enum.TryParse(fp.MonPatOption, out fpMonthlyPatternVariant)) { Logger.Log(LogSeverity.Warning, string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", "ScheduleManager", Environment.NewLine, "GetNextDate"), "Error parsing FrequencyPattern, fpMonthlyPatternVariant"); } DayOfWeek fpMonthlyPatternDayOfWeek; if (Enum.TryParse(fp.MonPatDayOfWeek, out fpMonthlyPatternDayOfWeek)) { Logger.Log(LogSeverity.Warning, string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", "ScheduleManager", Environment.NewLine, "GetNextDate"), "Error parsing FrequencyPattern, fpMonthlyPatternDayOfWeek"); } RecurYearlyOption fpRecurYearlyOption; if (Enum.TryParse(fp.YearPatRecurYearlyOption, out fpRecurYearlyOption)) { Logger.Log(LogSeverity.Warning, string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", "ScheduleManager", Environment.NewLine, "GetNextDate"), "Error parsing FrequencyPattern, fpRecurYearlyOption"); } YearlyPatternVariant fpYearlyPatternVariant; if (Enum.TryParse(fp.YearPatOption, out fpYearlyPatternVariant)) { Logger.Log(LogSeverity.Warning, string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", "ScheduleManager", Environment.NewLine, "GetNextDate"), "Error parsing FrequencyPattern, fpYearlyPatternVariant"); } DayOfWeek fpYearlyPatternDayOfWeek; if (Enum.TryParse(fp.YearPatDayOfWeek, out fpYearlyPatternDayOfWeek)) { Logger.Log(LogSeverity.Warning, string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", "ScheduleManager", Environment.NewLine, "GetNextDate"), "Error parsing FrequencyPattern, fpYearlyPatternDayOfWeek"); } TimeIntervalPosition fpYearlyPatternTimeIntervalPosition; if (Enum.TryParse(fp.YearPatTimeIntervalPosition, out fpYearlyPatternTimeIntervalPosition)) { Logger.Log(LogSeverity.Warning, string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", "ScheduleManager", Environment.NewLine, "GetNextDate"), "Error parsing FrequencyPattern, fpYearlyPatternTimeIntervalPosition"); } TimeIntervalPosition fpMonthlyPatternTimeIntervalPosition; if (Enum.TryParse(fp.MonPatTimeIntervalPosition, out fpMonthlyPatternTimeIntervalPosition)) { Logger.Log(LogSeverity.Warning, string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", "ScheduleManager", Environment.NewLine, "GetNextDate"), "Error parsing FrequencyPattern, fpMonthlyPatternTimeIntervalPosition"); } #endregion switch (fpType) { case FrequencyPatternType.Weekly: #region GetPreviousDate for Weekly pattern var currentDay = dateTime.DayOfWeek; var selectedDays = new List<DayOfWeek>(); if (fp.IsSundaySelected.GetValueOrDefault(false)) selectedDays.Add(DayOfWeek.Sunday); if (fp.IsMondaySelected.GetValueOrDefault(false)) selectedDays.Add(DayOfWeek.Monday); if (fp.IsTuesdaySelected.GetValueOrDefault(false)) selectedDays.Add(DayOfWeek.Tuesday); if (fp.IsWednesdaySelected.GetValueOrDefault(false)) selectedDays.Add(DayOfWeek.Wednesday); if (fp.IsThursdaySelected.GetValueOrDefault(false)) selectedDays.Add(DayOfWeek.Thursday); if (fp.IsFridaySelected.GetValueOrDefault(false)) selectedDays.Add(DayOfWeek.Friday); if (fp.IsSaturdaySelected.GetValueOrDefault(false)) selectedDays.Add(DayOfWeek.Saturday); var possibleDays = selectedDays.Where(x => x < currentDay).ToArray(); return possibleDays.Any() ? dateTime.AddDays(possibleDays.Max() - currentDay) : dateTime.AddDays((-fp.WeeklyPatternWeeksToRecur.GetValueOrDefault(0) * 7 + (selectedDays.Max() - currentDay))); #endregion case FrequencyPatternType.Monthly: #region GetPreviousDate for Monthly pattern DateTime previousMonth; switch (fpMonthlyPatternVariant) { case MonthlyPatternVariant.NumberOfMonths: { return dateTime.AddMonths(-fp.MonPatMonthsToRec.GetValueOrDefault(0)); } case MonthlyPatternVariant.DayByDate: { var currentDayOfMonth = dateTime.Day; var recurDate = fp.MonPatRecurDate > DateTime.DaysInMonth(dateTime.Year, dateTime.Month) ? DateTime.DaysInMonth(dateTime.Year, dateTime.Month) : fp.MonPatRecurDate; if (recurDate < currentDayOfMonth) { return dateTime.AddDays((double)(recurDate - currentDayOfMonth)); } previousMonth = dateTime.AddMonths(-fp.MonPatByDateOptionMonthsToRec.GetValueOrDefault(0)); return new DateTime(previousMonth.Year, previousMonth.Month, (fp.MonPatRecurDate.GetValueOrDefault(0) > DateTime.DaysInMonth(previousMonth.Year, previousMonth.Month) ? DateTime.DaysInMonth(previousMonth.Year, previousMonth.Month) : fp.MonPatRecurDate.GetValueOrDefault(0))); } case MonthlyPatternVariant.DayByPosition: previousMonth = dateTime.AddMonths(-fp.MonPatByPositionOptionMonToRec.GetValueOrDefault(0)); var basicDates = new List<object> { new { basicDate = previousMonth, firstDay = new DateTime(previousMonth.Year, previousMonth.Month, 1), lastDay = new DateTime(previousMonth.Year, previousMonth.Month, DateTime.DaysInMonth(previousMonth.Year, previousMonth.Month)) }, /* dateTime here is either Schedule based on or field to display schedule date. Fallback? */ new { basicDate = dateTime, firstDay = new DateTime(dateTime.Year, dateTime.Month, 1), lastDay = new DateTime(dateTime.Year, dateTime.Month, DateTime.DaysInMonth(dateTime.Year, dateTime.Month)) } }; foreach (var bd in basicDates) { DateTime testDate; var basicDate = (DateTime)bd.GetType().GetProperty("basicDate").GetValue(bd, null); var firstDay = (DateTime)bd.GetType().GetProperty("firstDay").GetValue(bd, null); var lastDay = (DateTime)bd.GetType().GetProperty("lastDay").GetValue(bd, null); if (fp.MonPatTimeIntervalPosition != TimeIntervalPosition.Last.ToString()) { if (fpMonthlyPatternDayOfWeek > firstDay.DayOfWeek) { testDate = new DateTime(basicDate.Year, basicDate.Month, 1 + (fpMonthlyPatternDayOfWeek - firstDay.DayOfWeek + 7 * (int)fpMonthlyPatternTimeIntervalPosition)); } else if (fpMonthlyPatternDayOfWeek < firstDay.DayOfWeek) { testDate = new DateTime(basicDate.Year, basicDate.Month, 1 + (7 - (firstDay.DayOfWeek - fpMonthlyPatternDayOfWeek) + 7 * (int)fpMonthlyPatternTimeIntervalPosition)); } else { testDate = new DateTime(basicDate.Year, basicDate.Month, 1 + 7 * (int)fpMonthlyPatternTimeIntervalPosition); } } else { if (fpMonthlyPatternDayOfWeek < lastDay.DayOfWeek) { testDate = new DateTime(basicDate.Year, basicDate.Month, lastDay.Day - (lastDay.DayOfWeek - fpMonthlyPatternDayOfWeek)); } else if (fpMonthlyPatternDayOfWeek > lastDay.DayOfWeek) { testDate = new DateTime(basicDate.Year, basicDate.Month, lastDay.Day - (7 - (fpMonthlyPatternDayOfWeek - lastDay.DayOfWeek))); } else { testDate = new DateTime(basicDate.Year, basicDate.Month, lastDay.Day); } } if (testDate > dateTime) return testDate; } break; } #endregion break; case FrequencyPatternType.Yearly: #region GetPreviousDate for Yearly pattern if (fpRecurYearlyOption == RecurYearlyOption.RecurYearly) { dateTime = dateTime.AddYears(-fp.YearPatYearsToRec.GetValueOrDefault(0)); break; } switch (fpYearlyPatternVariant) { case YearlyPatternVariant.DayByDate: var withinTheSameYear = new DateTime(dateTime.Year, DateTime.ParseExact( fp.YearPatByDateOptionSelectMon, "MMMM", new CultureInfo(Constants.DefaultCultureName)).Month, fp.YearPatDayOfSelectMon.GetValueOrDefault(0)); if (dateTime < withinTheSameYear) return withinTheSameYear; return new DateTime(-dateTime.AddYears(fp.YearPatYearsToRec.GetValueOrDefault(0)).Year, DateTime.ParseExact( fp.YearPatByDateOptionSelectMon, "MMMM", new CultureInfo(Constants.DefaultCultureName)).Month, fp.YearPatDayOfSelectMon.GetValueOrDefault(0)); case YearlyPatternVariant.DayByName: var nextYear = dateTime.AddYears(-fp.YearPatYearsToRec.GetValueOrDefault(0)); var selectedMonth = DateTime.ParseExact(fp.YearPatByNameOptionSelectMon, "MMMM", new CultureInfo(Constants.DefaultCultureName)).Month; var basicDates = new List<object> { new { basicDate = dateTime, firstDay = new DateTime(dateTime.Year, selectedMonth, 1), lastDay = new DateTime(dateTime.Year, selectedMonth, DateTime.DaysInMonth(dateTime.Year, selectedMonth)) }, new { basicDate = nextYear, firstDay = new DateTime(nextYear.Year, selectedMonth, 1), lastDay = new DateTime(nextYear.Year, selectedMonth, DateTime.DaysInMonth(nextYear.Year, selectedMonth)) } }; foreach (var bd in basicDates) { DateTime testDate; var basicDate = (DateTime)bd.GetType().GetProperty("basicDate").GetValue(bd, null); var firstDay = (DateTime)bd.GetType().GetProperty("firstDay").GetValue(bd, null); var lastDay = (DateTime)bd.GetType().GetProperty("lastDay").GetValue(bd, null); if (fp.YearPatTimeIntervalPosition != TimeIntervalPosition.Last.ToString()) { if (fpYearlyPatternDayOfWeek > firstDay.DayOfWeek) { testDate = new DateTime(basicDate.Year, firstDay.Month, 1 + (fpYearlyPatternDayOfWeek - firstDay.DayOfWeek + 7 * (int)fpYearlyPatternTimeIntervalPosition)); } else if (fpYearlyPatternDayOfWeek < firstDay.DayOfWeek) { testDate = new DateTime(basicDate.Year, firstDay.Month, 1 + (7 - (firstDay.DayOfWeek - fpYearlyPatternDayOfWeek) + 7 * (int)fpYearlyPatternTimeIntervalPosition)); } else { testDate = new DateTime(basicDate.Year, firstDay.Month, 1 + 7 * (int)fpYearlyPatternTimeIntervalPosition); } } else { if (fpYearlyPatternDayOfWeek < lastDay.DayOfWeek) { testDate = new DateTime(basicDate.Year, firstDay.Month, lastDay.Day - (lastDay.DayOfWeek - fpYearlyPatternDayOfWeek)); } else if (fpYearlyPatternDayOfWeek > lastDay.DayOfWeek) { testDate = new DateTime(basicDate.Year, firstDay.Month, lastDay.Day - (7 - (fpYearlyPatternDayOfWeek - lastDay.DayOfWeek))); } else { testDate = new DateTime(basicDate.Year, firstDay.Month, lastDay.Day); } } if (testDate > dateTime) return testDate; } break; } #endregion break; } return dateTime; }
private static DateTime GetNextDate(DateTime dateTime, IFrequencyPattern fp, ICalendar calendar) { fp.DisableBusinessRules(); #region Set FrequencyPatternType FrequencyPatternType fpType; if (!Enum.TryParse(fp.PatternType, out fpType)) { Logger.Log(LogSeverity.Warning, string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", "ScheduleManager", Environment.NewLine, "GetNextDate"), "Error parsing FrequencyPattern, fpType"); } DailyPatternVariant fpDailyPatternVariant; if (Enum.TryParse(fp.DailyPatternOption, out fpDailyPatternVariant)) { Logger.Log(LogSeverity.Warning, string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", "ScheduleManager", Environment.NewLine, "GetNextDate"), "Error parsing FrequencyPattern, fpDailyPatternVariant"); } MonthlyPatternVariant fpMonthlyPatternVariant; if (Enum.TryParse(fp.MonPatOption, out fpMonthlyPatternVariant)) { Logger.Log(LogSeverity.Warning, string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", "ScheduleManager", Environment.NewLine, "GetNextDate"), "Error parsing FrequencyPattern, fpMonthlyPatternVariant"); } DayOfWeek fpMonthlyPatternDayOfWeek; if (Enum.TryParse(fp.MonPatDayOfWeek, out fpMonthlyPatternDayOfWeek)) { Logger.Log(LogSeverity.Warning, string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", "ScheduleManager", Environment.NewLine, "GetNextDate"), "Error parsing FrequencyPattern, fpMonthlyPatternDayOfWeek"); } RecurYearlyOption fpRecurYearlyOption; if (Enum.TryParse(fp.YearPatRecurYearlyOption, out fpRecurYearlyOption)) { Logger.Log(LogSeverity.Warning, string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", "ScheduleManager", Environment.NewLine, "GetNextDate"), "Error parsing FrequencyPattern, fpRecurYearlyOption"); } YearlyPatternVariant fpYearlyPatternVariant; if (Enum.TryParse(fp.YearPatOption, out fpYearlyPatternVariant)) { Logger.Log(LogSeverity.Warning, string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", "ScheduleManager", Environment.NewLine, "GetNextDate"), "Error parsing FrequencyPattern, fpYearlyPatternVariant"); } DayOfWeek fpYearlyPatternDayOfWeek; if (Enum.TryParse(fp.YearPatDayOfWeek, out fpYearlyPatternDayOfWeek)) { Logger.Log(LogSeverity.Warning, string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", "ScheduleManager", Environment.NewLine, "GetNextDate"), "Error parsing FrequencyPattern, fpYearlyPatternDayOfWeek"); } TimeIntervalPosition fpYearlyPatternTimeIntervalPosition; if (Enum.TryParse(fp.YearPatTimeIntervalPosition, out fpYearlyPatternTimeIntervalPosition)) { Logger.Log(LogSeverity.Warning, string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", "ScheduleManager", Environment.NewLine, "GetNextDate"), "Error parsing FrequencyPattern, fpYearlyPatternTimeIntervalPosition"); } TimeIntervalPosition fpMonthlyPatternTimeIntervalPosition; if (Enum.TryParse(fp.MonPatTimeIntervalPosition, out fpMonthlyPatternTimeIntervalPosition)) { Logger.Log(LogSeverity.Warning, string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", "ScheduleManager", Environment.NewLine, "GetNextDate"), "Error parsing FrequencyPattern, fpMonthlyPatternTimeIntervalPosition"); } #endregion switch (fpType) { case FrequencyPatternType.Daily: #region GetNextDate for Daily pattern var nextDate = dateTime; if (calendar != null && calendar.WorkingIntervals != null && calendar.WorkingExceptions != null && calendar.WorkingIntervals.Any()) { var calendarWorkingIntervals = calendar.WorkingIntervals.Where(wi => wi.StartDate.HasValue && wi.FinishDate.HasValue && wi.StartDate.Value < wi.FinishDate.Value).ToList(); var calendarWorkingExceptions = calendar.WorkingExceptions.Where(we => we.StartDate.HasValue && we.FinishDate.HasValue && we.StartDate.Value < we.FinishDate.Value).ToList(); var isWorkingDay = false; short infiniteLoop = 0; while (!isWorkingDay) { infiniteLoop++; if (infiniteLoop > 100) { nextDate = fpDailyPatternVariant == DailyPatternVariant.WorkingDays ? dateTime.AddDays(1.0) : dateTime.AddDays(fp.DailyPatternDaysToRecur.GetValueOrDefault(0)); break; } var exception = GetWorkingException(nextDate, calendar, calendarWorkingIntervals, FrequencyPatternType.Daily); if (exception != null) { ExceptionBehavior exceptionBehavior = ExceptionBehavior.ScheduleAfter; if (!string.IsNullOrEmpty(exception.ExceptionBehavior) && !Enum.TryParse(exception.ExceptionBehavior, out exceptionBehavior)) exceptionBehavior = ExceptionBehavior.ScheduleAfter; switch (exceptionBehavior) { case ExceptionBehavior.Skip: case ExceptionBehavior.ScheduleAfter: var exceptionEndDate = exception.FinishDate.Value; nextDate = fpDailyPatternVariant == DailyPatternVariant.WorkingDays ? (new DateTime(exceptionEndDate.Year, exceptionEndDate.Month, exceptionEndDate.Day, nextDate.Hour, nextDate.Minute, nextDate.Second)).AddDays(1.0) : nextDate.AddDays(fp.DailyPatternDaysToRecur.GetValueOrDefault(0)); break; case ExceptionBehavior.ScheduleBefore: var exceptionStartDate = exception.StartDate.Value; nextDate = fpDailyPatternVariant == DailyPatternVariant.WorkingDays ? (new DateTime(exceptionStartDate.Year, exceptionStartDate.Month, exceptionStartDate.Day, nextDate.Hour, nextDate.Minute, nextDate.Second)).AddDays(-1.0) : nextDate.AddDays(-fp.DailyPatternDaysToRecur.GetValueOrDefault(0)); break; } } else { nextDate = fpDailyPatternVariant == DailyPatternVariant.WorkingDays ? nextDate.AddDays(1.0) : nextDate.AddDays(fp.DailyPatternDaysToRecur.GetValueOrDefault(0)); } if (!calendar.WorkingExceptions.Any()) { isWorkingDay = (from wi in calendarWorkingIntervals where nextDate.DayOfWeek.ToString() == wi.Weekday select wi).Any(); } else { /* var tryNextDate = GetTime(nextDate, calendar); if (tryNextDate.HasValue) { nextDate = tryNextDate.Value; isWorkingDay = (from wi in calendarWorkingIntervals where nextDate.DayOfWeek.ToString() == wi.Weekday select wi).Any(); } */ isWorkingDay = (from wi in calendarWorkingIntervals from we in calendarWorkingExceptions /* let peopleHaveToWork = ((nextDate.Date == we.StartDate.Value.Date & (wi.StartDate.Value.TimeOfDay < we.StartDate.Value.TimeOfDay)) || (nextDate.Date == we.FinishDate.Value.Date & (wi.FinishDate.Value.TimeOfDay > we.FinishDate.Value.TimeOfDay))) */ let res = nextDate.DayOfWeek.ToString() == wi.Weekday && //(peopleHaveToWork || !(from x in calendarWorkingExceptions let wiComplete = (from y in calendarWorkingIntervals where y.Weekday == nextDate.DayOfWeek.ToString() group y by y.Weekday into wiWide select new { Weekday = wiWide.Key, StartDate = wiWide.Min(st => st.StartDate.Value), FinishDate = wiWide.Max(ft => ft.FinishDate.Value) }).First() where ((nextDate.Date > x.StartDate.Value.Date || (nextDate.Date == x.StartDate.Value.Date & (wiComplete.StartDate.TimeOfDay >= x.StartDate.Value.TimeOfDay))) & (nextDate.Date < x.FinishDate.Value.Date || (nextDate.Date == x.FinishDate.Value.Date & (wiComplete.FinishDate.TimeOfDay <= x.FinishDate.Value.TimeOfDay)))) select x).Any()//) where res select res).FirstOrDefault(); } } return nextDate; } nextDate = fpDailyPatternVariant == DailyPatternVariant.WorkingDays ? nextDate.AddDays(1.0) : nextDate.AddDays(fp.DailyPatternDaysToRecur.GetValueOrDefault(0)); while (nextDate.DayOfWeek == DayOfWeek.Saturday || nextDate.DayOfWeek == DayOfWeek.Sunday) { nextDate = fpDailyPatternVariant == DailyPatternVariant.WorkingDays ? nextDate.AddDays(1.0) : nextDate.AddDays(fp.DailyPatternDaysToRecur.GetValueOrDefault(0)); } return nextDate; #endregion case FrequencyPatternType.Weekly: #region GetNextDate for Weekly pattern var currentDay = dateTime.DayOfWeek; var selectedDays = new List<DayOfWeek>(); if (fp.IsSundaySelected.GetValueOrDefault(false)) selectedDays.Add(DayOfWeek.Sunday); if (fp.IsMondaySelected.GetValueOrDefault(false)) selectedDays.Add(DayOfWeek.Monday); if (fp.IsTuesdaySelected.GetValueOrDefault(false)) selectedDays.Add(DayOfWeek.Tuesday); if (fp.IsWednesdaySelected.GetValueOrDefault(false)) selectedDays.Add(DayOfWeek.Wednesday); if (fp.IsThursdaySelected.GetValueOrDefault(false)) selectedDays.Add(DayOfWeek.Thursday); if (fp.IsFridaySelected.GetValueOrDefault(false)) selectedDays.Add(DayOfWeek.Friday); if (fp.IsSaturdaySelected.GetValueOrDefault(false)) selectedDays.Add(DayOfWeek.Saturday); var possibleDays = selectedDays.Where(x => x > currentDay).ToArray(); return possibleDays.Any() ? dateTime.AddDays(possibleDays.Min() - currentDay) : dateTime.AddDays((fp.WeeklyPatternWeeksToRecur.GetValueOrDefault(0) * 7 - (currentDay - selectedDays.Min()))); #endregion case FrequencyPatternType.Monthly: #region GetNextDate for Monthly pattern DateTime nextMonth; switch (fpMonthlyPatternVariant) { case MonthlyPatternVariant.NumberOfMonths: { return dateTime.AddMonths(fp.MonPatMonthsToRec.GetValueOrDefault(0)); } case MonthlyPatternVariant.DayByDate: { var currentDayOfMonth = dateTime.Day; var recurDate = fp.MonPatRecurDate > DateTime.DaysInMonth(dateTime.Year, dateTime.Month) ? DateTime.DaysInMonth(dateTime.Year, dateTime.Month) : fp.MonPatRecurDate; if (recurDate > currentDayOfMonth) { return dateTime.AddDays((double)(recurDate - currentDayOfMonth)); } nextMonth = dateTime.AddMonths(fp.MonPatByDateOptionMonthsToRec.GetValueOrDefault(0)); return new DateTime(nextMonth.Year, nextMonth.Month, (fp.MonPatRecurDate.GetValueOrDefault(0) > DateTime.DaysInMonth(nextMonth.Year, nextMonth.Month) ? DateTime.DaysInMonth(nextMonth.Year, nextMonth.Month) : fp.MonPatRecurDate.GetValueOrDefault(0))); } case MonthlyPatternVariant.DayByPosition: nextMonth = dateTime.AddMonths(fp.MonPatByPositionOptionMonToRec.GetValueOrDefault(0)); var basicDates = new List<object> { new { basicDate = nextMonth, firstDay = new DateTime(nextMonth.Year, nextMonth.Month, 1), lastDay = new DateTime(nextMonth.Year, nextMonth.Month, DateTime.DaysInMonth(nextMonth.Year, nextMonth.Month)) }, /* dateTime here is either Schedule based on or field to display schedule date. Fallback? */ new { basicDate = dateTime, firstDay = new DateTime(dateTime.Year, dateTime.Month, 1), lastDay = new DateTime(dateTime.Year, dateTime.Month, DateTime.DaysInMonth(dateTime.Year, dateTime.Month)) } }; foreach (var bd in basicDates) { DateTime testDate; var basicDate = (DateTime)bd.GetType().GetProperty("basicDate").GetValue(bd, null); var firstDay = (DateTime)bd.GetType().GetProperty("firstDay").GetValue(bd, null); var lastDay = (DateTime)bd.GetType().GetProperty("lastDay").GetValue(bd, null); if (fp.MonPatTimeIntervalPosition != TimeIntervalPosition.Last.ToString()) { if (fpMonthlyPatternDayOfWeek > firstDay.DayOfWeek) { testDate = new DateTime(basicDate.Year, basicDate.Month, 1 + (fpMonthlyPatternDayOfWeek - firstDay.DayOfWeek + 7 * (int)fpMonthlyPatternTimeIntervalPosition)); } else if (fpMonthlyPatternDayOfWeek < firstDay.DayOfWeek) { testDate = new DateTime(basicDate.Year, basicDate.Month, 1 + (7 - (firstDay.DayOfWeek - fpMonthlyPatternDayOfWeek) + 7 * (int)fpMonthlyPatternTimeIntervalPosition)); } else { testDate = new DateTime(basicDate.Year, basicDate.Month, 1 + 7 * (int)fpMonthlyPatternTimeIntervalPosition); } } else { if (fpMonthlyPatternDayOfWeek < lastDay.DayOfWeek) { testDate = new DateTime(basicDate.Year, basicDate.Month, lastDay.Day - (lastDay.DayOfWeek - fpMonthlyPatternDayOfWeek)); } else if (fpMonthlyPatternDayOfWeek > lastDay.DayOfWeek) { testDate = new DateTime(basicDate.Year, basicDate.Month, lastDay.Day - (7 - (fpMonthlyPatternDayOfWeek - lastDay.DayOfWeek))); } else { testDate = new DateTime(basicDate.Year, basicDate.Month, lastDay.Day); } } if (testDate > dateTime) return testDate; } break; } #endregion break; case FrequencyPatternType.Yearly: #region GetNextDate for Yearly pattern if (fpRecurYearlyOption == RecurYearlyOption.RecurYearly) { dateTime = dateTime.AddYears(fp.YearPatYearsToRec.GetValueOrDefault(0)); break; } switch (fpYearlyPatternVariant) { case YearlyPatternVariant.DayByDate: var withinTheSameYear = new DateTime(dateTime.Year, DateTime.ParseExact( fp.YearPatByDateOptionSelectMon, "MMMM", new CultureInfo(Constants.DefaultCultureName)).Month, fp.YearPatDayOfSelectMon.GetValueOrDefault(0)); if (dateTime < withinTheSameYear) return withinTheSameYear; return new DateTime(dateTime.AddYears(fp.YearPatYearsToRec.GetValueOrDefault(0)).Year, DateTime.ParseExact( fp.YearPatByDateOptionSelectMon, "MMMM", new CultureInfo(Constants.DefaultCultureName)).Month, fp.YearPatDayOfSelectMon.GetValueOrDefault(0)); case YearlyPatternVariant.DayByName: var nextYear = dateTime.AddYears(fp.YearPatYearsToRec.GetValueOrDefault(0)); var selectedMonth = DateTime.ParseExact(fp.YearPatByNameOptionSelectMon, "MMMM", new CultureInfo(Constants.DefaultCultureName)).Month; var basicDates = new List<object> { new { basicDate = dateTime, firstDay = new DateTime(dateTime.Year, selectedMonth, 1), lastDay = new DateTime(dateTime.Year, selectedMonth, DateTime.DaysInMonth(dateTime.Year, selectedMonth)) }, new { basicDate = nextYear, firstDay = new DateTime(nextYear.Year, selectedMonth, 1), lastDay = new DateTime(nextYear.Year, selectedMonth, DateTime.DaysInMonth(nextYear.Year, selectedMonth)) } }; foreach (var bd in basicDates) { DateTime testDate; var basicDate = (DateTime)bd.GetType().GetProperty("basicDate").GetValue(bd, null); var firstDay = (DateTime)bd.GetType().GetProperty("firstDay").GetValue(bd, null); var lastDay = (DateTime)bd.GetType().GetProperty("lastDay").GetValue(bd, null); if (fp.YearPatTimeIntervalPosition != TimeIntervalPosition.Last.ToString()) { if (fpYearlyPatternDayOfWeek > firstDay.DayOfWeek) { testDate = new DateTime(basicDate.Year, firstDay.Month, 1 + (fpYearlyPatternDayOfWeek - firstDay.DayOfWeek + 7 * (int)fpYearlyPatternTimeIntervalPosition)); } else if (fpYearlyPatternDayOfWeek < firstDay.DayOfWeek) { testDate = new DateTime(basicDate.Year, firstDay.Month, 1 + (7 - (firstDay.DayOfWeek - fpYearlyPatternDayOfWeek) + 7 * (int)fpYearlyPatternTimeIntervalPosition)); } else { testDate = new DateTime(basicDate.Year, firstDay.Month, 1 + 7 * (int)fpYearlyPatternTimeIntervalPosition); } } else { if (fpYearlyPatternDayOfWeek < lastDay.DayOfWeek) { testDate = new DateTime(basicDate.Year, firstDay.Month, lastDay.Day - (lastDay.DayOfWeek - fpYearlyPatternDayOfWeek)); } else if (fpYearlyPatternDayOfWeek > lastDay.DayOfWeek) { testDate = new DateTime(basicDate.Year, firstDay.Month, lastDay.Day - (7 - (fpYearlyPatternDayOfWeek - lastDay.DayOfWeek))); } else { testDate = new DateTime(basicDate.Year, firstDay.Month, lastDay.Day); } } if (testDate > dateTime) return testDate; } break; } #endregion break; } return dateTime; }
/// <summary> /// Calculates the next date. /// </summary> /// <param name="dateTime">The date time.</param> /// <param name="fp">The fp.</param> /// <param name="calendar">The calendar.</param> /// <returns>DateTime.</returns> private static DateTime CalculateNextDate(DateTime dateTime, IFrequencyPattern fp, ICalendar calendar) { var nextdate = GetNextDate(dateTime, fp, calendar); var nextDateTime = GetTime(nextdate, calendar); return nextDateTime ?? nextdate; }
/// <summary> /// Calculates the and save. /// </summary> /// <param name="nextdate">The next date.</param> /// <param name="info">The information.</param> /// <param name="scheduleEdit">The schedule edit.</param> /// <param name="fp">The fp.</param> /// <param name="calendar">The calendar.</param> /// <exception cref="Cebos.Veyron.SharedTypes.VeyronException"></exception> private static void CalculateAndSave(ref DateTime nextdate, IInfoClass info, ISupportScheduling scheduleEdit, IFrequencyPattern fp, ICalendar calendar) { var edit = info == null ? TheDynamicTypeManager.NewEditableRoot<ISupportScheduling>(scheduleEdit.ProcessName) : TheDynamicTypeManager.GetEditableRoot<ISupportScheduling>(scheduleEdit.ProcessName, info.Id); if (!edit.IsNew && scheduleEdit.SchedulingSeriesItemNumber > edit.SchedulingSeriesItemNumber) return; scheduleEdit.CopyScheduledPropertiesTo(edit); nextdate = CalculateNextDate(nextdate, fp, calendar); if (scheduleEdit.SchedulingEndOption == SchedulingEndOption.EndByDate.ToString() && nextdate > scheduleEdit.SchedulingEndByDate) { return; } edit.ScheduleDisplayDate = fp.PatternType.Equals(FrequencyPatternType.Daily.ToString()) ? nextdate : CheckAdjustWorkingExceptions(ref nextdate, calendar, fp); //duplicated due to exceptions, go to next frequency while ((_scheduledList.Contains(((DateTime)edit.ScheduleDisplayDate).Date) || _previousScheduleDate > ((DateTime)edit.ScheduleDisplayDate).Date) && calendar != null) { nextdate = CalculateNextDate(nextdate, fp, calendar); if (scheduleEdit.SchedulingEndOption == SchedulingEndOption.EndByDate.ToString() && nextdate > scheduleEdit.SchedulingEndByDate) { return; } edit.ScheduleDisplayDate = fp.PatternType.Equals(FrequencyPatternType.Daily.ToString()) ? nextdate : CheckAdjustWorkingExceptions(ref nextdate, calendar, fp); } _scheduledList.Add(((DateTime)edit.ScheduleDisplayDate).Date); _previousScheduleDate = ((DateTime)edit.ScheduleDisplayDate).Date; edit.SchedulingSeriesGuid = scheduleEdit.SchedulingSeriesGuid; edit.SchedulingEndOption = scheduleEdit.SchedulingEndOption; edit.SchedulingEndAfterOccurrences = scheduleEdit.SchedulingEndAfterOccurrences; edit.SchedulingEndAfterOccurrencesIndex = scheduleEdit.SchedulingEndAfterOccurrencesIndex; edit.SchedulingEndByDate = scheduleEdit.SchedulingEndByDate; edit.ScheduledItemsCount = scheduleEdit.ScheduledItemsCount; edit.SchedulingFrequencyPatternId = scheduleEdit.SchedulingFrequencyPatternId; edit.ProcessingScheduling = true; var businessBase = edit as BusinessBase; if (businessBase != null && !businessBase.IsValid) { var allValidationErrors = businessBase.BrokenRulesCollection.Select(x => string.IsNullOrEmpty(x.Description) ? x.RuleName : x.Description).ToList(); var parent = edit.GetBaseEdit() as BusinessBase; if (parent != null && !parent.IsValid) allValidationErrors.AddRange(parent.BrokenRulesCollection.Select(x => string.IsNullOrEmpty(x.Description) ? x.RuleName : x.Description).ToList()); throw new VeyronException(string.Format(CultureInfo.InvariantCulture, "Scheduled process '{0}' is not valid and cannot be saved{1}{2}", edit.ProcessDisplayName, Environment.NewLine, string.Join(Environment.NewLine, allValidationErrors))); } var savedObject = (ISupportScheduling)((ISavable)edit).Save(); scheduleEdit.CopyScheduledPropertiesAfterEditableRootWasSaved(savedObject); }
/// <summary> /// Get a valid previous working day without exception. /// </summary> /// <param name="nextDate"></param> /// <param name="calendar"></param> /// <param name="fp"></param> /// <returns></returns> private static DateTime CheckAdjustPreviousWorkingExceptions(ref DateTime nextDate, ICalendar calendar, IFrequencyPattern fp) { DateTime scheduledDate; var workingIntervals = GetPreviousWorkingIntervals(out scheduledDate, nextDate, calendar); if (workingIntervals == null || !workingIntervals.Any()) return nextDate; var exception = GetWorkingException(scheduledDate, calendar, workingIntervals); if (exception == null) return scheduledDate; var dayBeforeException = exception.StartDate == null ? scheduledDate : exception.StartDate.Value.AddDays(-1); return CheckAdjustPreviousWorkingExceptions(ref dayBeforeException, calendar, fp); }
/// <summary>If there is a working exception, try to find available day on the same week.</summary> /// <param name="nextDate">Scheduled next date.</param> /// <param name="calendar">The calendar.</param> /// <param name="fp"></param> /// <returns>Scheduled next date adjusted for an exception.</returns> private static DateTime CheckAdjustWorkingExceptions(ref DateTime nextDate, ICalendar calendar, IFrequencyPattern fp) { DateTime scheduledDate; var workingIntervals = GetWorkingIntervals(out scheduledDate, nextDate, calendar); if (workingIntervals == null || !workingIntervals.Any()) return nextDate; var exception = GetWorkingException(scheduledDate, calendar, workingIntervals); if (exception == null) return scheduledDate; ExceptionBehavior exceptionBehavior = ExceptionBehavior.ScheduleAfter; if (!string.IsNullOrEmpty(exception.ExceptionBehavior) && !Enum.TryParse(exception.ExceptionBehavior, out exceptionBehavior)) exceptionBehavior = ExceptionBehavior.ScheduleAfter; switch (exceptionBehavior) { case ExceptionBehavior.Skip: scheduledDate = nextDate = GetNextDate(scheduledDate, fp, calendar); break; case ExceptionBehavior.ScheduleAfter: scheduledDate = exception.FinishDate == null ? scheduledDate : exception.FinishDate.Value.AddDays(1); GetWorkingIntervals(out scheduledDate, scheduledDate, calendar); break; case ExceptionBehavior.ScheduleBefore: var dayBeforeException = exception.StartDate == null ? scheduledDate : exception.StartDate.Value.AddDays(-1); return CheckAdjustPreviousWorkingExceptions(ref dayBeforeException,calendar,fp); } return CheckAdjustWorkingExceptions(ref scheduledDate, calendar, fp); }