public Calendar next(Calendar earliest)
    {
        CronTime time = new CronTime(earliest);

        while (!fields[MONTH].isAllowed(time))
        {
            time.incMonth(1);
            time.resetDayOfMonth();
            time.resetHour();
            time.resetMinute();
        }

        boolean special = fields[DAY_OF_MONTH].isRestricted() && fields[DAY_OF_WEEK].isRestricted();

        if (special)
        {
            // either day of month or day of week may match
            while ((!fields[DAY_OF_MONTH].isAllowed(time)) && (!fields[DAY_OF_WEEK].isAllowed(time)))
            {
                time.incDayOfMonth(1);
                time.resetHour();
                time.resetMinute();
            }
        }
        else
        {
            // day of month and day of week must match
            while ((!fields[DAY_OF_MONTH].isAllowed(time)) || (!fields[DAY_OF_WEEK].isAllowed(time)))
            {
                time.incDayOfMonth(1);
                time.resetHour();
                time.resetMinute();
            }
        }

        while (!fields[HOUR].isAllowed(time))
        {
            time.incHour(1);
            time.resetMinute();
        }

        while (!fields[MINUTE].isAllowed(time))
        {
            time.incMinute(1);
        }

        return time.getCalendar();
    }