如何使 Quartz 每 n 个月启动一次作业,一月份没有中断



我希望 Quartz 每五个月在每三个月的第五天执行作业。我是这样做的:0 0 10 ?*/5 5#3

问题是在这种情况下,

cron 调度程序绑定到年份。所以实际上它在每年的 1、6、11 个月执行计划。但我希望它从本月开始透明地执行。比如明年 4、9、2,明年 7 等。怎么能做到呢?

我知道有CalendarIntervalSchedule可以做到这一点,但它不允许我做"每三周的第五天"。

Quartz 调度程序允许您为每个作业指定多个 CronTrigger。因此,您可以创建几个较小的表达式来协同工作,而不是创建单个多用途表达式。

我想出了这些:

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

唯一的缺点是您必须在一开始就指定起始年份,但我想您可以轻松地将其自动化。

祝你好运!;)

不要认为你可以用一个规则来做到这一点。

您必须创建多个规则来显式指定月份和年份组合:

0 0 10 ? 1,6,11 5#3 2015,2020,2025,2030
0 0 10 ? 4,9 5#3 2016,2021,2026,2031
0 0 10 ? 2,7,12 5#3 2017,2022,2027,2032
0 0 10 ? 5,10 5#3 2018,2023,2028,2033
0 0 10 ? 3,8 5#3 2019,2024,2029,2034

对于我的任务,我找到了更好的解决方案。我创建了一个日历,其中仅包括从指定日期开始的月份,具有指定的间隔。所有其他月份将被拒绝。

这对我来说更容易,因为我不需要为工作创建/管理很多触发器。

[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);
    }
}

最新更新