如何让 Quartz 每第 n 个月启动一次工作而不会在一月份中断?
How to make Quartz launch job every nth month with no interrupt at january?
我希望 Quartz 在每五个月的每个第三周的第五天执行作业。我这样做:
0 0 10 ? */5 5#3
问题是 cron 调度程序在这种情况下绑定到年份。所以实际上它在每年的1、6、11月执行计划。
但我希望它从当月开始透明地执行。比如明年4、9、2,明年7e.t.c。
怎么做到的?
我知道有 CalendarIntervalSchedule 可以执行此操作,但它不允许我执行此操作 "fifth day of every third week"。
不要认为你可以用一条规则做到这一点。
您必须创建多个明确指定月份和年份组合的规则:
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
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
唯一的缺点是您必须在一开始就指定开始年份,但我想您可以轻松地实现自动化。
祝你好运! ;)
对于我的任务,我找到了更好的解决方案。我创建了一个日历,其中仅包含从指定日期开始的指定时间间隔的月份。所有其他月份将被拒绝。
这对我来说更容易,因为我不需要 create/manage 很多工作的触发器。
[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);
}
}
我希望 Quartz 在每五个月的每个第三周的第五天执行作业。我这样做: 0 0 10 ? */5 5#3
问题是 cron 调度程序在这种情况下绑定到年份。所以实际上它在每年的1、6、11月执行计划。 但我希望它从当月开始透明地执行。比如明年4、9、2,明年7e.t.c。 怎么做到的?
我知道有 CalendarIntervalSchedule 可以执行此操作,但它不允许我执行此操作 "fifth day of every third week"。
不要认为你可以用一条规则做到这一点。
您必须创建多个明确指定月份和年份组合的规则:
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
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
唯一的缺点是您必须在一开始就指定开始年份,但我想您可以轻松地实现自动化。
祝你好运! ;)
对于我的任务,我找到了更好的解决方案。我创建了一个日历,其中仅包含从指定日期开始的指定时间间隔的月份。所有其他月份将被拒绝。
这对我来说更容易,因为我不需要 create/manage 很多工作的触发器。
[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);
}
}