Esempio n. 1
0
        /// <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);
        }
Esempio n. 2
0
        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));
            }
        }