Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make Quartz launch job every nth month with no interrupt at january?

I want Quartz to execute job every on the fifth day of every third week of every fifth month. I do it like this: 0 0 10 ? */5 5#3

The problem is cron scheduler is bound to year in this case. So actually it executes schedule on 1, 6, 11 month of every year. But I want it to execute transparently starting from current month. Like 4, 9, 2 next year, 7 next year e.t.c. How can one do it?

I know there's CalendarIntervalSchedule which does this but it doesn't allow me to do "fifth day of every third week".

like image 678
norekhov Avatar asked Feb 02 '26 19:02

norekhov


2 Answers

Quartz scheduler lets you specify more than one CronTrigger per job. So instead of creating a single multipurpose expression you can create few smaller expressions to work together.

I came up with these:

0 0 10 ? 1,6,11 5#3 2015/5
0 0 10 ? 4,9 5#3 2016/5
0 0 10 ? 2,7,12 5#3 2017/5
0 0 10 ? 5,10 5#3 2018/5
0 0 10 ? 3,8 5#3 2019/5

The only drawback is that you would have to specify the starting years at the very beginning, but I guess you can automate it easily.

Good luck! ;)

like image 149
Igor Avatar answered Feb 05 '26 09:02

Igor


For my task I found a better solution. I created a calendar which will include only months starting at specified date with specified interval. All other months will be rejected.

It's easier for me cause I don't need to create/manage a lot of triggers for a job.

[Serializable]
public class MonthIntervalCalendar : BaseCalendar
{
    DateTime _startAt;
    int _interval;

    /// <summary>
    /// Initializes a new instance of the <see cref="MonthIntervalCalendar"/> class.
    /// </summary>
    public MonthIntervalCalendar(DateTime startAt, int interval)
    {
        _startAt = startAt;
        _interval = interval;
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="MonthIntervalCalendar"/> class.
    /// </summary>
    /// <param name="baseCalendar">The base calendar.</param>
    public MonthIntervalCalendar(DateTime startAt, int interval, ICalendar baseCalendar)
    {
        _startAt = startAt;
        _interval = interval;
        CalendarBase = baseCalendar;
    }

    public override bool IsTimeIncluded(DateTimeOffset timeStampUtc)
    {
        if (!base.IsTimeIncluded(timeStampUtc))
            return false;
        if (timeStampUtc < _startAt)
            return false;

        var months = (timeStampUtc.Month - _startAt.Month) + 12 * (timeStampUtc.Year - _startAt.Year);
        var included = months % _interval == 0;
        return included;
    }

    /// <summary>
    /// Determine the next time (in milliseconds) that is 'included' by the
    /// Calendar after the given time.
    /// <para>
    /// Note that this Calendar is only has full-day precision.
    /// </para>
    /// </summary>
    public override DateTimeOffset GetNextIncludedTimeUtc(DateTimeOffset timeUtc)
    {
        timeUtc = base.GetNextIncludedTimeUtc(timeUtc);
        while (!IsTimeIncluded(timeUtc))
        {
            var nextTime = timeUtc.AddMonths(1);
            timeUtc = base.GetNextIncludedTimeUtc( new DateTime(nextTime.Year, nextTime.Month, 1) );
        }
        return timeUtc;
    }

    /// <summary>
    /// Creates a new object that is a copy of the current instance.
    /// </summary>
    /// <returns>A new object that is a copy of this instance.</returns>
    public override object Clone()
    {
        MonthIntervalCalendar clone = (MonthIntervalCalendar)base.Clone();
        clone._interval = _interval;
        clone._startAt = _startAt;
        return clone;
    }

    public override int GetHashCode()
    {
        int baseHash = 0;
        if (GetBaseCalendar() != null)
            baseHash = GetBaseCalendar().GetHashCode();
        return _startAt.GetHashCode() + _interval + 5 * baseHash;
    }

    public bool Equals(MonthIntervalCalendar obj)
    {
        if (obj == null)
            return false;
        bool baseEqual = GetBaseCalendar() == null || GetBaseCalendar().Equals(obj.GetBaseCalendar());

        return baseEqual && obj._startAt.Equals(_startAt) && obj._interval.Equals(_interval);
    }

    public override bool Equals(object obj)
    {
        if ((obj == null) || !(obj is MonthIntervalCalendar))
            return false;
        return Equals((MonthIntervalCalendar)obj);
    }
}
like image 21
norekhov Avatar answered Feb 05 '26 09:02

norekhov