private bool IsDayOfWeekMatch(int year, int month, int day)
        {
            if (HasFlag(CronExpressionFlag.DayOfWeekLast) && !CalendarHelper.IsLastDayOfWeek(year, month, day) ||
                HasFlag(CronExpressionFlag.NthDayOfWeek) && !CalendarHelper.IsNthDayOfWeek(day, _nthDayOfWeek))
            {
                return(false);
            }

            if (_dayOfWeek == CronField.DaysOfWeek.AllBits)
            {
                return(true);
            }

            var dayOfWeek = CalendarHelper.GetDayOfWeek(year, month, day);

            return(((_dayOfWeek >> (int)dayOfWeek) & 1) != 0);
        }
 private int GetLastDayOfMonth(int year, int month)
 {
     return(CalendarHelper.GetDaysInMonth(year, month) - _lastMonthOffset);
 }
        private long FindOccurence(long ticks, bool startInclusive)
        {
            if (!startInclusive)
            {
                ticks++;
            }

            CalendarHelper.FillDateTimeParts(
                ticks,
                out int startSecond,
                out int startMinute,
                out int startHour,
                out int startDay,
                out int startMonth,
                out int startYear);

            var minMatchedDay = GetFirstSet(_dayOfMonth);

            var second = startSecond;
            var minute = startMinute;
            var hour   = startHour;
            var day    = startDay;
            var month  = startMonth;
            var year   = startYear;

            if (!GetBit(_second, second) && !Move(_second, ref second))
            {
                minute++;
            }
            if (!GetBit(_minute, minute) && !Move(_minute, ref minute))
            {
                hour++;
            }
            if (!GetBit(_hour, hour) && !Move(_hour, ref hour))
            {
                day++;
            }

            // If NearestWeekday flag is set it's possible forward shift.
            if (HasFlag(CronExpressionFlag.NearestWeekday))
            {
                day = CronField.DaysOfMonth.First;
            }

            if (!GetBit(_dayOfMonth, day) && !Move(_dayOfMonth, ref day))
            {
                goto RetryMonth;
            }
            if (!GetBit(_month, month))
            {
                goto RetryMonth;
            }

Retry:

            if (day > GetLastDayOfMonth(year, month))
            {
                goto RetryMonth;
            }

            if (HasFlag(CronExpressionFlag.DayOfMonthLast))
            {
                day = GetLastDayOfMonth(year, month);
            }

            var lastCheckedDay = day;

            if (HasFlag(CronExpressionFlag.NearestWeekday))
            {
                day = CalendarHelper.MoveToNearestWeekDay(year, month, day);
            }

            if (IsDayOfWeekMatch(year, month, day))
            {
                if (CalendarHelper.IsGreaterThan(year, month, day, startYear, startMonth, startDay))
                {
                    goto RolloverDay;
                }
                if (hour > startHour)
                {
                    goto RolloverHour;
                }
                if (minute > startMinute)
                {
                    goto RolloverMinute;
                }
                goto ReturnResult;

                RolloverDay    : hour   = GetFirstSet(_hour);
                RolloverHour   : minute = GetFirstSet(_minute);
                RolloverMinute : second = GetFirstSet(_second);

ReturnResult:

                var found = CalendarHelper.DateTimeToTicks(year, month, day, hour, minute, second);
                if (found >= ticks)
                {
                    return(found);
                }
            }

            day = lastCheckedDay;
            if (Move(_dayOfMonth, ref day))
            {
                goto Retry;
            }

RetryMonth:

            if (!Move(_month, ref month) && ++year >= MaxYear)
            {
                return(NotFound);
            }
            day = minMatchedDay;

            goto Retry;
        }