public void CheckCorrectWZone( ScheduleSpec spec, string nowWZone, string expectedWZone) { var nowDate = DateTimeParsingFunctions.ParseDefaultMSecWZone(nowWZone); var expectedDate = DateTimeParsingFunctions.ParseDefaultMSecWZone(expectedWZone); var result = ScheduleComputeHelper.ComputeNextOccurance( spec, nowDate, TimeZoneInfo.Utc, TimeAbacusMilliseconds.INSTANCE); var resultDate = DateTimeEx.GetInstance(TimeZoneInfo.Utc, result); if (result != expectedDate) { Log.Debug( ".checkCorrect Difference in result found, spec=" + spec); Log.Debug( ".checkCorrect now=" + timeFormat.Format(nowDate.TimeFromMillis()) + " long=" + nowDate); Log.Debug( ".checkCorrect expected=" + timeFormat.Format(expectedDate.TimeFromMillis()) + " long=" + expectedDate); Log.Debug( ".checkCorrect result=" + timeFormat.Format(resultDate) + " long=" + resultDate.UtcMillis); Assert.IsTrue(false); } }
public void TestValidate() { // Test all units missing IDictionary <ScheduleUnit, ICollection <int> > unitValues = new Dictionary <ScheduleUnit, ICollection <int> >(); AssertInvalid(unitValues); // Test one unit missing unitValues = new ScheduleSpec().UnitValues; unitValues.Remove(ScheduleUnit.HOURS); AssertInvalid(unitValues); // Test all units are wildcards unitValues = new ScheduleSpec().UnitValues; new ScheduleSpec(unitValues, null, null, null); // Test invalid value in month ICollection <int> values = new SortedSet <int>(); values.Add(0); unitValues.Put(ScheduleUnit.MONTHS, values); AssertInvalid(unitValues); // Test valid value in month values = new SortedSet <int>(); values.Add(1); values.Add(5); unitValues.Put(ScheduleUnit.MONTHS, values); new ScheduleSpec(unitValues, null, null, null); }
public void CheckCorrect( ScheduleSpec spec, string now, string expected) { var nowDate = timeFormat.Parse(now); var expectedDate = timeFormat.Parse(expected); var result = ScheduleComputeHelper.ComputeNextOccurance( spec, nowDate.UtcMillis, TimeZoneInfo.Utc, TimeAbacusMilliseconds.INSTANCE); var resultDate = DateTimeEx.GetInstance(TimeZoneInfo.Utc, result); if (!resultDate.Equals(expectedDate)) { Log.Debug(".checkCorrect Difference in result found, spec=" + spec); Log.Debug( ".checkCorrect now=" + timeFormat.Format(nowDate) + " long=" + nowDate.UtcMillis); Log.Debug( ".checkCorrect expected=" + timeFormat.Format(expectedDate) + " long=" + expectedDate.UtcMillis); Log.Debug( ".checkCorrect result=" + timeFormat.Format(resultDate) + " long=" + resultDate.UtcMillis); Assert.IsTrue(false); } }
/// <summary> /// Computes the next lowest date in milliseconds based on a specification and the /// from-time passed in and returns the delta from the current time. /// </summary> /// <param name="spec">The schedule.</param> /// <param name="afterTimeInMillis">defines the start time.</param> /// <param name="timeZone">The time zone.</param> /// <param name="timeAbacus">The time abacus.</param> /// <returns> /// a long millisecond value representing the delta between current time and the next schedule occurance matching the spec /// </returns> public static long ComputeDeltaNextOccurance( ScheduleSpec spec, long afterTimeInMillis, TimeZoneInfo timeZone, TimeAbacus timeAbacus) { return(ComputeNextOccurance(spec, afterTimeInMillis, timeZone, timeAbacus) - afterTimeInMillis); }
public void TestCompress() { IDictionary <ScheduleUnit, ICollection <int> > unitValues = new Dictionary <ScheduleUnit, ICollection <int> >(); unitValues = new ScheduleSpec().UnitValues; // Populate Month with all valid values ICollection <int> monthValues = new SortedSet <int>(); for (var i = ScheduleUnit.MONTHS.Min(); i <= ScheduleUnit.MONTHS.Max(); i++) { monthValues.Add(i); } unitValues.Put(ScheduleUnit.MONTHS, monthValues); // Construct spec, test that month was replaced with wildcards var spec = new ScheduleSpec(unitValues, null, null, null); Assert.IsTrue(spec.UnitValues.Get(ScheduleUnit.MONTHS) == null); }
/// <summary> /// Computes the next lowest date in milliseconds based on a specification and the /// from-time passed in. /// </summary> /// <param name="spec">defines the schedule</param> /// <param name="afterTimeInMillis">defines the start time</param> /// <param name="timeZone">The time zone.</param> /// <param name="timeAbacus">The time abacus.</param> /// <returns> /// a long date tick value for the next schedule occurance matching the spec /// </returns> public static long ComputeNextOccurance( ScheduleSpec spec, long afterTimeInMillis, TimeZoneInfo timeZone, TimeAbacus timeAbacus) { if (ExecutionPathDebugLog.IsDebugEnabled && Log.IsDebugEnabled) { Log.Debug( ".computeNextOccurance Computing next occurance," + " afterTimeInTicks=" + afterTimeInMillis.TimeFromMillis(timeZone) + " as long=" + afterTimeInMillis + " spec=" + spec); } // Add the minimum resolution to the Start time to ensure we don't get the same exact time if (spec.UnitValues.ContainsKey(ScheduleUnit.MICROSECONDS) && timeAbacus.OneSecond == 1000000L) { afterTimeInMillis += 1; } else if (spec.UnitValues.ContainsKey(ScheduleUnit.MILLISECONDS)) { afterTimeInMillis += timeAbacus.OneSecond / 1000; } else if (spec.UnitValues.ContainsKey(ScheduleUnit.SECONDS)) { afterTimeInMillis += timeAbacus.OneSecond; } else { afterTimeInMillis += 60 * timeAbacus.OneSecond; } return(Compute(spec, afterTimeInMillis, timeZone, timeAbacus)); }
public void TestCompute() { ScheduleSpec spec = null; // Try next "5 minutes past the hour" spec = new ScheduleSpec(); spec.AddValue(ScheduleUnit.MINUTES, 5); CheckCorrect(spec, "2004-12-9 15:45:01", "2004-12-9 16:05:00"); CheckCorrect(spec, "2004-12-9 16:04:59", "2004-12-9 16:05:00"); CheckCorrect(spec, "2004-12-9 16:05:00", "2004-12-9 17:05:00"); CheckCorrect(spec, "2004-12-9 16:05:01", "2004-12-9 17:05:00"); CheckCorrect(spec, "2004-12-9 16:05:01", "2004-12-9 17:05:00"); CheckCorrect(spec, "2004-12-9 23:58:01", "2004-12-10 00:05:00"); // Try next "5, 10 and 15 minutes past the hour" spec = new ScheduleSpec(); spec.AddValue(ScheduleUnit.MINUTES, 5); spec.AddValue(ScheduleUnit.MINUTES, 10); spec.AddValue(ScheduleUnit.MINUTES, 15); CheckCorrect(spec, "2004-12-9 15:45:01", "2004-12-9 16:05:00"); CheckCorrect(spec, "2004-12-9 16:04:59", "2004-12-9 16:05:00"); CheckCorrect(spec, "2004-12-9 16:05:00", "2004-12-9 16:10:00"); CheckCorrect(spec, "2004-12-9 16:10:00", "2004-12-9 16:15:00"); CheckCorrect(spec, "2004-12-9 16:14:59", "2004-12-9 16:15:00"); CheckCorrect(spec, "2004-12-9 16:15:00", "2004-12-9 17:05:00"); // Try next "0 and 30 and 59 minutes past the hour" spec = new ScheduleSpec(); spec.AddValue(ScheduleUnit.MINUTES, 0); spec.AddValue(ScheduleUnit.MINUTES, 30); spec.AddValue(ScheduleUnit.MINUTES, 59); CheckCorrect(spec, "2004-12-9 15:45:01", "2004-12-9 15:59:00"); CheckCorrect(spec, "2004-12-9 15:59:01", "2004-12-9 16:00:00"); CheckCorrect(spec, "2004-12-9 16:04:59", "2004-12-9 16:30:00"); CheckCorrect(spec, "2004-12-9 16:30:00", "2004-12-9 16:59:00"); CheckCorrect(spec, "2004-12-9 16:59:30", "2004-12-9 17:00:00"); // Try minutes combined with seconds spec = new ScheduleSpec(); spec.AddValue(ScheduleUnit.MINUTES, 0); spec.AddValue(ScheduleUnit.MINUTES, 30); spec.AddValue(ScheduleUnit.SECONDS, 0); spec.AddValue(ScheduleUnit.SECONDS, 30); CheckCorrect(spec, "2004-12-9 15:59:59", "2004-12-9 16:00:00"); CheckCorrect(spec, "2004-12-9 16:00:00", "2004-12-9 16:00:30"); CheckCorrect(spec, "2004-12-9 16:00:29", "2004-12-9 16:00:30"); CheckCorrect(spec, "2004-12-9 16:00:30", "2004-12-9 16:30:00"); CheckCorrect(spec, "2004-12-9 16:29:59", "2004-12-9 16:30:00"); CheckCorrect(spec, "2004-12-9 16:30:00", "2004-12-9 16:30:30"); CheckCorrect(spec, "2004-12-9 17:00:00", "2004-12-9 17:00:30"); // Try hours combined with seconds spec = new ScheduleSpec(); for (var i = 10; i <= 14; i++) { spec.AddValue(ScheduleUnit.HOURS, i); } spec.AddValue(ScheduleUnit.SECONDS, 15); CheckCorrect(spec, "2004-12-9 15:59:59", "2004-12-10 10:00:15"); CheckCorrect(spec, "2004-12-10 10:00:15", "2004-12-10 10:01:15"); CheckCorrect(spec, "2004-12-10 10:01:15", "2004-12-10 10:02:15"); CheckCorrect(spec, "2004-12-10 14:01:15", "2004-12-10 14:02:15"); CheckCorrect(spec, "2004-12-10 14:59:15", "2004-12-11 10:00:15"); // Try hours combined with minutes spec = new ScheduleSpec(); spec.AddValue(ScheduleUnit.HOURS, 9); spec.AddValue(ScheduleUnit.MINUTES, 5); CheckCorrect(spec, "2004-12-9 15:59:59", "2004-12-10 9:05:00"); CheckCorrect(spec, "2004-11-30 15:59:59", "2004-12-1 9:05:00"); CheckCorrect(spec, "2004-11-30 9:04:59", "2004-11-30 9:05:00"); CheckCorrect(spec, "2004-12-31 9:05:01", "2005-01-01 9:05:00"); // Try day of month as the 31st spec = new ScheduleSpec(); spec.AddValue(ScheduleUnit.DAYS_OF_MONTH, 31); CheckCorrect(spec, "2004-11-30 15:59:59", "2004-12-31 0:00:00"); CheckCorrect(spec, "2004-12-30 15:59:59", "2004-12-31 0:00:00"); CheckCorrect(spec, "2004-12-31 00:00:00", "2004-12-31 0:01:00"); CheckCorrect(spec, "2005-01-01 00:00:00", "2005-01-31 0:00:00"); CheckCorrect(spec, "2005-02-01 00:00:00", "2005-03-31 0:00:00"); CheckCorrect(spec, "2005-04-01 00:00:00", "2005-05-31 0:00:00"); // Try day of month as the 29st, for february testing spec = new ScheduleSpec(); spec.AddValue(ScheduleUnit.DAYS_OF_MONTH, 29); CheckCorrect(spec, "2004-11-30 15:59:59", "2004-12-29 0:00:00"); CheckCorrect(spec, "2004-12-29 00:00:00", "2004-12-29 0:01:00"); CheckCorrect(spec, "2004-12-29 00:01:00", "2004-12-29 0:02:00"); CheckCorrect(spec, "2004-02-28 15:59:59", "2004-02-29 0:00:00"); CheckCorrect(spec, "2003-02-28 15:59:59", "2003-03-29 0:00:00"); CheckCorrect(spec, "2005-02-27 15:59:59", "2005-03-29 0:00:00"); // Try 4:00 every day spec = new ScheduleSpec(); spec.AddValue(ScheduleUnit.HOURS, 16); spec.AddValue(ScheduleUnit.MINUTES, 0); CheckCorrect(spec, "2004-10-01 15:59:59", "2004-10-01 16:00:00"); CheckCorrect(spec, "2004-10-01 00:00:00", "2004-10-01 16:00:00"); CheckCorrect(spec, "2004-09-30 16:00:00", "2004-10-01 16:00:00"); CheckCorrect(spec, "2004-12-30 16:00:00", "2004-12-31 16:00:00"); CheckCorrect(spec, "2004-12-31 16:00:00", "2005-01-01 16:00:00"); // Try every weekday at 10 am - scrum time! spec = new ScheduleSpec(); spec.AddValue(ScheduleUnit.HOURS, 10); spec.AddValue(ScheduleUnit.MINUTES, 0); for (var i = 1; i <= 5; i++) { spec.AddValue(ScheduleUnit.DAYS_OF_WEEK, i); } CheckCorrect(spec, "2004-12-05 09:50:59", "2004-12-06 10:00:00"); CheckCorrect(spec, "2004-12-06 09:59:59", "2004-12-06 10:00:00"); CheckCorrect(spec, "2004-12-07 09:50:00", "2004-12-07 10:00:00"); CheckCorrect(spec, "2004-12-08 09:00:00", "2004-12-08 10:00:00"); CheckCorrect(spec, "2004-12-09 08:00:00", "2004-12-09 10:00:00"); CheckCorrect(spec, "2004-12-10 09:50:50", "2004-12-10 10:00:00"); CheckCorrect(spec, "2004-12-11 00:00:00", "2004-12-13 10:00:00"); CheckCorrect(spec, "2004-12-12 09:00:50", "2004-12-13 10:00:00"); CheckCorrect(spec, "2004-12-13 09:50:50", "2004-12-13 10:00:00"); CheckCorrect(spec, "2004-12-13 10:00:00", "2004-12-14 10:00:00"); CheckCorrect(spec, "2004-12-13 10:00:01", "2004-12-14 10:00:00"); // Every Monday and also on the 1st and 15th of each month, at midnight // (tests the or between DAYS_OF_MONTH and DAYS_OF_WEEK) spec = new ScheduleSpec(); spec.AddValue(ScheduleUnit.DAYS_OF_MONTH, 1); spec.AddValue(ScheduleUnit.DAYS_OF_MONTH, 15); spec.AddValue(ScheduleUnit.HOURS, 0); spec.AddValue(ScheduleUnit.MINUTES, 0); spec.AddValue(ScheduleUnit.SECONDS, 0); spec.AddValue(ScheduleUnit.DAYS_OF_WEEK, 1); CheckCorrect(spec, "2004-12-05 09:50:59", "2004-12-06 00:00:00"); CheckCorrect(spec, "2004-12-06 00:00:00", "2004-12-13 00:00:00"); CheckCorrect(spec, "2004-12-07 01:20:00", "2004-12-13 00:00:00"); CheckCorrect(spec, "2004-12-12 23:00:00", "2004-12-13 00:00:00"); CheckCorrect(spec, "2004-12-13 23:00:00", "2004-12-15 00:00:00"); CheckCorrect(spec, "2004-12-14 23:00:00", "2004-12-15 00:00:00"); CheckCorrect(spec, "2004-12-15 23:00:00", "2004-12-20 00:00:00"); CheckCorrect(spec, "2004-12-18 23:00:00", "2004-12-20 00:00:00"); CheckCorrect(spec, "2004-12-20 00:01:00", "2004-12-27 00:00:00"); CheckCorrect(spec, "2004-12-27 00:01:00", "2005-01-01 00:00:00"); CheckCorrect(spec, "2005-01-01 00:01:00", "2005-01-03 00:00:00"); CheckCorrect(spec, "2005-01-03 00:01:00", "2005-01-10 00:00:00"); CheckCorrect(spec, "2005-01-10 00:01:00", "2005-01-15 00:00:00"); CheckCorrect(spec, "2005-01-15 00:01:00", "2005-01-17 00:00:00"); CheckCorrect(spec, "2005-01-17 00:01:00", "2005-01-24 00:00:00"); CheckCorrect(spec, "2005-01-24 00:01:00", "2005-01-31 00:00:00"); CheckCorrect(spec, "2005-01-31 00:01:00", "2005-02-01 00:00:00"); // Every second month on every second weekday spec = new ScheduleSpec(); for (var i = 1; i <= 12; i += 2) { spec.AddValue(ScheduleUnit.MONTHS, i); } for (var i = 0; i <= 6; i += 2) // Adds Sunday, Tuesday, Thursday, Saturday { spec.AddValue(ScheduleUnit.DAYS_OF_WEEK, i); } CheckCorrect(spec, "2004-09-01 00:00:00", "2004-09-02 00:00:00"); // Sept 1 2004 is a Wednesday CheckCorrect(spec, "2004-09-02 00:00:00", "2004-09-02 00:01:00"); CheckCorrect(spec, "2004-09-02 23:59:00", "2004-09-04 00:00:00"); CheckCorrect(spec, "2004-09-04 23:59:00", "2004-09-05 00:00:00"); // Sept 5 2004 is a Sunday CheckCorrect(spec, "2004-09-05 23:57:00", "2004-09-05 23:58:00"); CheckCorrect(spec, "2004-09-05 23:58:00", "2004-09-05 23:59:00"); CheckCorrect(spec, "2004-09-05 23:59:00", "2004-09-07 00:00:00"); CheckCorrect(spec, "2004-09-30 23:58:00", "2004-09-30 23:59:00"); // Sept 30 in a Thursday CheckCorrect(spec, "2004-09-30 23:59:00", "2004-11-02 00:00:00"); // Every second month on every second weekday spec = new ScheduleSpec(); for (var i = 1; i <= 12; i += 2) { spec.AddValue(ScheduleUnit.MONTHS, i); } for (var i = 0; i <= 6; i += 2) // Adds Sunday, Tuesday, Thursday, Saturday { spec.AddValue(ScheduleUnit.DAYS_OF_WEEK, i); } CheckCorrect(spec, "2004-09-01 00:00:00", "2004-09-02 00:00:00"); // Sept 1 2004 is a Wednesday CheckCorrect(spec, "2004-09-02 00:00:00", "2004-09-02 00:01:00"); CheckCorrect(spec, "2004-09-02 23:59:00", "2004-09-04 00:00:00"); CheckCorrect(spec, "2004-09-04 23:59:00", "2004-09-05 00:00:00"); // Sept 5 2004 is a Sunday CheckCorrect(spec, "2004-09-05 23:57:00", "2004-09-05 23:58:00"); CheckCorrect(spec, "2004-09-05 23:58:00", "2004-09-05 23:59:00"); CheckCorrect(spec, "2004-09-05 23:59:00", "2004-09-07 00:00:00"); // Every 5 seconds, between 9am and until 4pm, all weekdays except Saturday and Sunday spec = new ScheduleSpec(); for (var i = 0; i <= 59; i += 5) { spec.AddValue(ScheduleUnit.SECONDS, i); } for (var i = 1; i <= 5; i++) { spec.AddValue(ScheduleUnit.DAYS_OF_WEEK, i); } for (var i = 9; i <= 15; i++) { spec.AddValue(ScheduleUnit.HOURS, i); } CheckCorrect(spec, "2004-12-12 20:00:00", "2004-12-13 09:00:00"); // Dec 12 2004 is a Sunday CheckCorrect(spec, "2004-12-13 09:00:01", "2004-12-13 09:00:05"); CheckCorrect(spec, "2004-12-13 09:00:05", "2004-12-13 09:00:10"); CheckCorrect(spec, "2004-12-13 09:00:11", "2004-12-13 09:00:15"); CheckCorrect(spec, "2004-12-13 09:00:15", "2004-12-13 09:00:20"); CheckCorrect(spec, "2004-12-13 09:00:24", "2004-12-13 09:00:25"); CheckCorrect(spec, "2004-12-13 15:59:50", "2004-12-13 15:59:55"); CheckCorrect(spec, "2004-12-13 15:59:55", "2004-12-14 09:00:00"); CheckCorrect(spec, "2004-12-14 12:27:35", "2004-12-14 12:27:40"); CheckCorrect(spec, "2004-12-14 12:29:55", "2004-12-14 12:30:00"); CheckCorrect(spec, "2004-12-17 00:03:00", "2004-12-17 09:00:00"); CheckCorrect(spec, "2004-12-17 15:59:50", "2004-12-17 15:59:55"); CheckCorrect(spec, "2004-12-17 15:59:55", "2004-12-20 09:00:00"); // Feb 14, 12pm spec = new ScheduleSpec(); spec.AddValue(ScheduleUnit.MONTHS, 2); spec.AddValue(ScheduleUnit.DAYS_OF_MONTH, 14); spec.AddValue(ScheduleUnit.HOURS, 12); spec.AddValue(ScheduleUnit.MINUTES, 0); CheckCorrect(spec, "2004-12-12 20:00:00", "2005-02-14 12:00:00"); CheckCorrect(spec, "2003-12-12 20:00:00", "2004-02-14 12:00:00"); CheckCorrect(spec, "2004-02-01 20:00:00", "2004-02-14 12:00:00"); // Dec 31, 23pm and 50 seconds (countdown) spec = new ScheduleSpec(); spec.AddValue(ScheduleUnit.MONTHS, 12); spec.AddValue(ScheduleUnit.DAYS_OF_MONTH, 31); spec.AddValue(ScheduleUnit.HOURS, 23); spec.AddValue(ScheduleUnit.MINUTES, 59); spec.AddValue(ScheduleUnit.SECONDS, 50); CheckCorrect(spec, "2004-12-12 20:00:00", "2004-12-31 23:59:50"); CheckCorrect(spec, "2004-12-31 23:59:55", "2005-12-31 23:59:50"); // CST timezone 7:00:00am spec = new ScheduleSpec(); spec.AddValue(ScheduleUnit.HOURS, 7); spec.AddValue(ScheduleUnit.MINUTES, 0); spec.AddValue(ScheduleUnit.SECONDS, 0); spec.OptionalTimeZone = "Central Standard Time"; CheckCorrectWZone(spec, "2008-02-01T06:00:00.000GMT-10:00", "2008-02-02T03:00:00.000GMT-10:00"); CheckCorrectWZone(spec, "2008-02-01T06:00:00.000GMT-9:00", "2008-02-02T04:00:00.000GMT-9:00"); CheckCorrectWZone(spec, "2008-02-01T06:00:00.000GMT-8:00", "2008-02-02T05:00:00.000GMT-8:00"); CheckCorrectWZone(spec, "2008-02-01T06:00:00.000GMT-7:00", "2008-02-02T06:00:00.000GMT-7:00"); CheckCorrectWZone(spec, "2008-02-01T06:00:00.000GMT-6:00", "2008-02-01T07:00:00.000GMT-6:00"); CheckCorrectWZone(spec, "2008-02-01T06:00:00.000GMT-5:00", "2008-02-01T08:00:00.000GMT-5:00"); CheckCorrectWZone(spec, "2008-02-01T06:00:00.000GMT-4:00", "2008-02-01T09:00:00.000GMT-4:00"); // EST timezone 7am, any minute spec = new ScheduleSpec(); spec.AddValue(ScheduleUnit.HOURS, 7); spec.AddValue(ScheduleUnit.SECONDS, 0); spec.OptionalTimeZone = "Eastern Standard Time"; CheckCorrectWZone(spec, "2008-02-01T06:00:00.000GMT-7:00", "2008-02-02T05:00:00.000GMT-7:00"); CheckCorrectWZone(spec, "2008-02-01T06:00:00.000GMT-6:00", "2008-02-01T06:01:00.000GMT-6:00"); CheckCorrectWZone(spec, "2008-02-01T06:00:00.000GMT-5:00", "2008-02-01T07:00:00.000GMT-5:00"); CheckCorrectWZone(spec, "2008-02-01T06:00:00.000GMT-4:00", "2008-02-01T08:00:00.000GMT-4:00"); }
/// <summary> /// Determine the next valid day of month based on the given specification of valid days in month and /// valid days in week. If both days in week and days in month are supplied, the days are OR-ed. /// </summary> /// <param name="spec"></param> /// <param name="after"></param> /// <param name="result"></param> /// <returns></returns> private static int DetermineDayOfMonth( ScheduleSpec spec, DateTimeEx after, ScheduleCalendar result) { ICollection <int> daysOfMonthSet = spec.UnitValues.Get(ScheduleUnit.DAYS_OF_MONTH); ICollection <int> daysOfWeekSet = spec.UnitValues.Get(ScheduleUnit.DAYS_OF_WEEK); ICollection <int> secondsSet = spec.UnitValues.Get(ScheduleUnit.SECONDS); ICollection <int> minutesSet = spec.UnitValues.Get(ScheduleUnit.MINUTES); ICollection <int> hoursSet = spec.UnitValues.Get(ScheduleUnit.HOURS); int dayOfMonth; // If days of week is a wildcard, just go by days of month if (spec.OptionalDayOfMonthOperator != null || spec.OptionalDayOfWeekOperator != null) { var isWeek = false; var op = spec.OptionalDayOfMonthOperator; if (spec.OptionalDayOfMonthOperator == null) { op = spec.OptionalDayOfWeekOperator; isWeek = true; } // may return the current day or a future day in the same month, // and may advance the "after" date to the next month int currentYYMMDD = GetTimeYYYYMMDD(after); IncreaseAfterDayOfMonthSpecialOp(op.Operator, op.Day, op.Month, isWeek, after); int rolledYYMMDD = GetTimeYYYYMMDD(after); // if rolled then reset time portion if (rolledYYMMDD > currentYYMMDD) { result.Second = (NextValue(secondsSet, 0)); result.Minute = (NextValue(minutesSet, 0)); result.Hour = (NextValue(hoursSet, 0)); return(after.GetFieldValue(DateTimeFieldEnum.DAY_OF_MONTH)); } // rolling backwards is not allowed else if (rolledYYMMDD < currentYYMMDD) { throw new IllegalStateException( "Failed to evaluate special date op, rolled date less then current date"); } else { var work = new DateTimeEx(after); work.SetFieldValue(DateTimeFieldEnum.SECOND, result.Second); work.SetFieldValue(DateTimeFieldEnum.MINUTE, result.Minute); work.SetFieldValue(DateTimeFieldEnum.HOUR_OF_DAY, result.Hour); if (work <= after) // new date is not after current date, so bump { after.AddUsingField(DateTimeFieldEnum.DAY_OF_MONTH, 1); result.Second = NextValue(secondsSet, 0); result.Minute = NextValue(minutesSet, 0); result.Hour = NextValue(hoursSet, 0); IncreaseAfterDayOfMonthSpecialOp(op.Operator, op.Day, op.Month, isWeek, after); } return(after.GetFieldValue(DateTimeFieldEnum.DAY_OF_MONTH)); } } else if (daysOfWeekSet == null) { dayOfMonth = NextValue(daysOfMonthSet, after.Day); if (dayOfMonth != after.Day) { result.Second = NextValue(secondsSet, 0); result.Minute = NextValue(minutesSet, 0); result.Hour = NextValue(hoursSet, 0); } if (dayOfMonth == -1) { dayOfMonth = NextValue(daysOfMonthSet, 0); after.AddMonths(1, DateTimeMathStyle.Java); } } // If days of weeks is not a wildcard and days of month is a wildcard, go by days of week only else if (daysOfMonthSet == null) { // Loop to find the next day of month that works for the specified day of week values while (true) { dayOfMonth = after.Day; int dayOfWeek = (int)after.DayOfWeek; // TODO // // Check the DayOfWeek logic in this section. The former code reads something // like the following: // // Calendar.Get(after, SupportClass.CalendarManager.DAY_OF_WEEK) - 1; // // Java calendars are one based which means that subtracting one makes them // zero-based. CLR DateTimes are zero-based so there should be no need to // tweak the dates to make this work. // If the day matches neither the day of month nor the day of week if (!daysOfWeekSet.Contains(dayOfWeek)) { result.Second = NextValue(secondsSet, 0); result.Minute = NextValue(minutesSet, 0); result.Hour = NextValue(hoursSet, 0); after.AddDays(1, DateTimeMathStyle.Java); } else { break; } } } // Both days of weeks and days of month are not a wildcard else { // Loop to find the next day of month that works for either day of month OR day of week while (true) { dayOfMonth = after.Day; int dayOfWeek = (int)after.DayOfWeek; // TODO // // See my discussion above about day of week conversion // If the day matches neither the day of month nor the day of week if ((!daysOfWeekSet.Contains(dayOfWeek)) && (!daysOfMonthSet.Contains(dayOfMonth))) { result.Second = NextValue(secondsSet, 0); result.Minute = NextValue(minutesSet, 0); result.Hour = NextValue(hoursSet, 0); after.AddDays(1, DateTimeMathStyle.Java); } else { break; } } } return(dayOfMonth); }
private static long Compute( ScheduleSpec spec, long afterTimeInMillis, TimeZoneInfo timeZone, TimeAbacus timeAbacus) { ICollection <int> minutesSet = spec.UnitValues.Get(ScheduleUnit.MINUTES); ICollection <int> hoursSet = spec.UnitValues.Get(ScheduleUnit.HOURS); ICollection <int> monthsSet = spec.UnitValues.Get(ScheduleUnit.MONTHS); bool isSecondsSpecified = spec.UnitValues.ContainsKey(ScheduleUnit.SECONDS); ICollection <int> secondsSet = isSecondsSpecified ? spec.UnitValues.Get(ScheduleUnit.SECONDS) : null; bool isMillisecondsSpecified = spec.UnitValues.ContainsKey(ScheduleUnit.MILLISECONDS); ICollection <int> millisecondsSet = isMillisecondsSpecified ? spec.UnitValues.Get(ScheduleUnit.MILLISECONDS) : null; bool isMicrosecondsSpecified = spec.UnitValues.ContainsKey(ScheduleUnit.MICROSECONDS); ICollection <int> microsecondsSet = isMillisecondsSpecified ? spec.UnitValues.Get(ScheduleUnit.MICROSECONDS) : null; while (true) { DateTimeEx after; if (spec.OptionalTimeZone != null) { try { timeZone = TimeZoneHelper.GetTimeZoneInfo(spec.OptionalTimeZone); after = DateTimeEx.GetInstance(timeZone); } catch (TimeZoneNotFoundException) { // this behavior ensures we are consistent with Java, but IMO, it's bad behavior... // basically, if the timezone is not found, we default to UTC. timeZone = TimeZoneInfo.Utc; after = DateTimeEx.GetInstance(timeZone); } } else { after = DateTimeEx.GetInstance(timeZone); } var remainder = timeAbacus.DateTimeSet(afterTimeInMillis, after); var result = new ScheduleCalendar { Milliseconds = after.Millisecond }; if (isMicrosecondsSpecified) { long nextValue = NextValue(microsecondsSet, (int)remainder); remainder = nextValue; if (nextValue == -1) { nextValue = NextValue(microsecondsSet, 0); remainder = nextValue; after.AddMilliseconds(1); } } else { result.Milliseconds = after.Millisecond; } if (isMillisecondsSpecified) { result.Milliseconds = NextValue(millisecondsSet, after.Millisecond); if (result.Milliseconds == -1) { result.Milliseconds = NextValue(millisecondsSet, 0); after.AddSeconds(1); } } else { result.Milliseconds = after.Millisecond; } if (isSecondsSpecified) { result.Second = NextValue(secondsSet, after.Second); if (result.Second == -1) { result.Second = NextValue(secondsSet, 0); after.AddMinutes(1); } } result.Minute = NextValue(minutesSet, after.Minute); if (result.Minute != after.Minute) { result.Second = NextValue(secondsSet, 0); } if (result.Minute == -1) { result.Minute = NextValue(minutesSet, 0); after.AddHours(1); } result.Hour = NextValue(hoursSet, after.Hour); if (result.Hour != after.Hour) { result.Second = NextValue(secondsSet, 0); result.Minute = NextValue(minutesSet, 0); } if (result.Hour == -1) { result.Hour = NextValue(hoursSet, 0); after.AddDays(1, DateTimeMathStyle.Java); } // This call may change second, minute and/or hour parameters // They may be reset to minimum values if the day rolled result.DayOfMonth = DetermineDayOfMonth(spec, after, result); bool dayMatchRealDate = false; while (!dayMatchRealDate) { if (CheckDayValidInMonth(timeZone, result.DayOfMonth, after.Month, after.Year)) { dayMatchRealDate = true; } else { after.AddMonths(1, DateTimeMathStyle.Java); } } int currentMonth = after.Month; result.Month = NextValue(monthsSet, currentMonth); if (result.Month != currentMonth) { result.Second = NextValue(secondsSet, 0); result.Minute = NextValue(minutesSet, 0); result.Hour = NextValue(hoursSet, 0); result.DayOfMonth = DetermineDayOfMonth(spec, after, result); } if (result.Month == -1) { result.Month = NextValue(monthsSet, 0); after.AddYears(1); } // Perform a last valid date check, if failing, try to compute a new date based on this altered after date int year = after.Year; if (!CheckDayValidInMonth(timeZone, result.DayOfMonth, result.Month, year)) { afterTimeInMillis = timeAbacus.DateTimeGet(after, remainder); continue; } return(GetTime(result, after.Year, spec.OptionalTimeZone, timeZone, timeAbacus, remainder)); } }