private static void CompileExpression(IrGroup irGroup, ExpressionNode expression) { foreach (var arg in expression.Arguments) { switch (expression.ExpressionType) { case ExpressionType.Seconds: CompileSecondsArgument(irGroup, arg); break; case ExpressionType.Minutes: CompileMinutesArgument(irGroup, arg); break; case ExpressionType.Hours: CompileHoursArgument(irGroup, arg); break; case ExpressionType.DaysOfWeek: CompileDaysOfWeekArgument(irGroup, arg); break; case ExpressionType.DaysOfMonth: CompileDaysOfMonthArgument(irGroup, arg); break; case ExpressionType.Dates: CompileDateArgument(irGroup, arg); break; default: throw new Exception("Expression type " + expression.ExpressionType + " not supported by the schyntax compiler." + SchyntaxException.PLEASE_REPORT_BUG_MSG); } } }
private static void CompileDateArgument(IrGroup irGroup, ArgumentNode arg) { IrDate irStart; IrDate?irEnd = null; var isSplit = false; if (arg.IsWildcard) { irStart = new IrDate(null, 1, 1); irEnd = new IrDate(null, 12, 31); } else { var start = (DateValueNode)arg.Range.Start; irStart = new IrDate(start.Year, start.Month, start.Day); if (arg.Range.End != null) { var end = (DateValueNode)arg.Range.End; irEnd = new IrDate(end.Year, end.Month, end.Day); } else if (arg.HasInterval) { // if there is an interval, but no end value specified, then the end value is implied irEnd = new IrDate(null, 12, 31); } // check for split range (spans January 1) - not applicable for dates with explicit years if (irEnd.HasValue && !start.Year.HasValue) { if (irStart.Month >= irEnd.Value.Month && (irStart.Month > irEnd.Value.Month || irStart.Day > irEnd.Value.Day)) { isSplit = true; } } } var irArg = new IrDateRange(irStart, irEnd, arg.HasInterval ? arg.IntervalValue : 0, isSplit, arg.Range?.IsHalfOpen ?? false); (arg.IsExclusion ? irGroup.DatesExcluded : irGroup.Dates).Add(irArg); }
private static void CompileDateArgument(IrGroup irGroup, ArgumentNode arg) { IrDate irStart; IrDate? irEnd = null; var isSplit = false; if (arg.IsWildcard) { irStart = new IrDate(null, 1, 1); irEnd = new IrDate(null, 12, 31); } else { var start = (DateValueNode)arg.Range.Start; irStart = new IrDate(start.Year, start.Month, start.Day); if (arg.Range.End != null) { var end = (DateValueNode)arg.Range.End; irEnd = new IrDate(end.Year, end.Month, end.Day); } else if (arg.HasInterval) { // if there is an interval, but no end value specified, then the end value is implied irEnd = new IrDate(null, 12, 31); } // check for split range (spans January 1) - not applicable for dates with explicit years if (irEnd.HasValue && !start.Year.HasValue) { if (irStart.Month >= irEnd.Value.Month && (irStart.Month > irEnd.Value.Month || irStart.Day > irEnd.Value.Day)) { isSplit = true; } } } var irArg = new IrDateRange(irStart, irEnd, arg.HasInterval ? arg.IntervalValue : 0, isSplit, arg.Range?.IsHalfOpen ?? false); (arg.IsExclusion ? irGroup.DatesExcluded : irGroup.Dates).Add(irArg); }
private static IrGroup CompileGroup(IReadOnlyList <ExpressionNode> expressions) { if (expressions == null || expressions.Count == 0) { return(null); } var irGroup = new IrGroup(); foreach (var expression in expressions) { CompileExpression(irGroup, expression); } // setup implied rules if (irGroup.HasSeconds || irGroup.HasSecondsExcluded) { // don't need to setup any defaults if seconds are defined } else if (irGroup.HasMinutes || irGroup.HasMinutesExcluded) { irGroup.Seconds.Add(GetZeroInteger()); } else if (irGroup.HasHours || irGroup.HasHoursExcluded) { irGroup.Seconds.Add(GetZeroInteger()); irGroup.Minutes.Add(GetZeroInteger()); } else // only a date level expression was set { irGroup.Seconds.Add(GetZeroInteger()); irGroup.Minutes.Add(GetZeroInteger()); irGroup.Hours.Add(GetZeroInteger()); } return(irGroup); }
private static void CompileDaysOfYearArgument(IrGroup irGroup, ArgumentNode arg) { var irArg = CompileIntegerArgument(arg, 1, 366); (arg.IsExclusion ? irGroup.DaysOfYearExcluded : irGroup.DaysOfYear).Add(irArg); }
private static void CompileHoursArgument(IrGroup irGroup, ArgumentNode arg) { var irArg = CompileIntegerArgument(arg, 0, 23); (arg.IsExclusion ? irGroup.HoursExcluded : irGroup.Hours).Add(irArg); }
private static void CompileMinutesArgument(IrGroup irGroup, ArgumentNode arg) { var irArg = CompileIntegerArgument(arg, 0, 59); (arg.IsExclusion ? irGroup.MinutesExcluded : irGroup.Minutes).Add(irArg); }
private static void CompileExpression(IrGroup irGroup, ExpressionNode expression) { foreach (var arg in expression.Arguments) { switch (expression.ExpressionType) { case ExpressionType.Seconds: CompileSecondsArgument(irGroup, arg); break; case ExpressionType.Minutes: CompileMinutesArgument(irGroup, arg); break; case ExpressionType.Hours: CompileHoursArgument(irGroup, arg); break; case ExpressionType.DaysOfWeek: CompileDaysOfWeekArgument(irGroup, arg); break; case ExpressionType.DaysOfMonth: CompileDaysOfMonthArgument(irGroup, arg); break; case ExpressionType.DaysOfYear: CompileDaysOfYearArgument(irGroup, arg); break; case ExpressionType.Dates: CompileDateArgument(irGroup, arg); break; default: throw new Exception("Expression type " + expression.ExpressionType + " not supported by the schyntax compiler." + SchyntaxException.PLEASE_REPORT_BUG_MSG); } } }
private static void CompileSecondsArgument(IrGroup irGroup, ArgumentNode arg) { var irArg = CompileIntegerArgument(arg, 0, 59); (arg.IsExclusion ? irGroup.SecondsExcluded : irGroup.Seconds).Add(irArg); }
private static IrGroup CompileGroup(IReadOnlyList<ExpressionNode> expressions) { if (expressions == null || expressions.Count == 0) return null; var irGroup = new IrGroup(); foreach (var expression in expressions) { CompileExpression(irGroup, expression); } // setup implied rules if (irGroup.HasSeconds || irGroup.HasSecondsExcluded) { // don't need to setup any defaults if seconds are defined } else if (irGroup.HasMinutes || irGroup.HasMinutesExcluded) { irGroup.Seconds.Add(GetZeroInteger()); } else if (irGroup.HasHours || irGroup.HasHoursExcluded) { irGroup.Seconds.Add(GetZeroInteger()); irGroup.Minutes.Add(GetZeroInteger()); } else // only a date level expression was set { irGroup.Seconds.Add(GetZeroInteger()); irGroup.Minutes.Add(GetZeroInteger()); irGroup.Hours.Add(GetZeroInteger()); } return irGroup; }
// yes yes, I know it's complicated, but settle down ReSharper // ReSharper disable once FunctionComplexityOverflow private static bool TryGetGroupEvent(IrGroup group, DateTimeOffset start, SearchMode mode, out DateTimeOffset result) { var after = mode == SearchMode.After; var inc = after ? 1 : -1; // used for incrementing values up or down depending on the direction we're searching var initHour = after ? 0 : 23; var initMinute = after ? 0 : 59; var initSecond = after ? 0 : 59; // todo: make the length of the search configurable for (var d = 0; d < 367; d++) { DateTimeOffset date; int hour, minute, second; if (d == 0) { // "after" events must be in the future date = after ? start.AddSeconds(1) : start; hour = date.Hour; minute = date.Minute; second = date.Second; } else { date = start.AddDays(d * inc); hour = initHour; minute = initMinute; second = initSecond; } var year = date.Year; var month = date.Month; var dayOfWeek = (int)date.DayOfWeek + 1; // DayOfWeek enum is zero-indexed var dayOfMonth = date.Day; var daysInMonth = DateTime.DaysInMonth(year, month); // check if today is an applicable date if (group.HasDates) { var applicable = false; foreach (var range in group.Dates) { if (InDateRange(range, year, month, dayOfMonth)) { applicable = true; break; } } if (!applicable) goto CONTINUE_DATE_LOOP; } if (group.HasDatesExcluded) { foreach (var range in group.DatesExcluded) { if (InDateRange(range, year, month, dayOfMonth)) goto CONTINUE_DATE_LOOP; } } // check if date is an applicable day of month if (group.HasDaysOfMonth) { var applicable = false; foreach (var range in group.DaysOfMonth) { if (InDayOfMonthRange(range, year, month, dayOfMonth)) { applicable = true; break; } } if (!applicable) goto CONTINUE_DATE_LOOP; } if (group.HasDaysOfMonthExcluded) { foreach (var range in group.DaysOfMonthExcluded) { if (InDayOfMonthRange(range, year, month, dayOfMonth)) goto CONTINUE_DATE_LOOP; } } // check if date is an applicable day of week if (group.HasDaysOfWeek && !InRule(7, group.DaysOfWeek, dayOfWeek)) goto CONTINUE_DATE_LOOP; if (group.HasDaysOfWeekExcluded && InRule(7, group.DaysOfWeekExcluded, dayOfWeek)) goto CONTINUE_DATE_LOOP; // if we've gotten this far, then today is an applicable day, let's keep going with hour checks var hourCount = after ? 24 - hour : hour + 1; for (; hourCount-- > 0; hour += inc, minute = initMinute, second = initSecond) { if (group.HasHours && !InRule(24, group.Hours, hour)) continue; if (group.HasHoursExcluded && InRule(24, group.HoursExcluded, hour)) continue; // if we've gotten here, the date and hour are valid. Let's check for minutes var minuteCount = after ? 60 - minute : minute + 1; for (; minuteCount-- > 0; minute += inc, second = initSecond) { if (group.HasMinutes && !InRule(60, group.Minutes, minute)) continue; if (group.HasMinutesExcluded && InRule(60, group.MinutesExcluded, minute)) continue; // check for valid seconds var secondCount = after ? 60 - second : second + 1; for (; secondCount-- > 0; second += inc) { if (group.HasSeconds && !InRule(60, group.Seconds, second)) continue; if (group.HasSecondsExcluded && InRule(60, group.SecondsExcluded, second)) continue; // we've found our event result = new DateTimeOffset(year, month, dayOfMonth, hour, minute, second, TimeSpan.Zero); return true; } } } CONTINUE_DATE_LOOP:; } // we didn't find an applicable date result = default(DateTimeOffset); return false; }