0
# Recurrence Rules
1
2
Flexible recurrence rule system for defining complex scheduling patterns with precise control over timing components in Node Schedule.
3
4
## Capabilities
5
6
### RecurrenceRule Class
7
8
Create complex recurring schedules using rule-based specifications with fine-grained control over timing.
9
10
```javascript { .api }
11
/**
12
* Create a recurrence rule for complex scheduling patterns
13
* @param {number|number[]|Range} [year] - Year specification
14
* @param {number|number[]|Range} [month] - Month specification (0-11, where 0=January)
15
* @param {number|number[]|Range} [date] - Day of month specification (1-31)
16
* @param {number|number[]|Range} [dayOfWeek] - Day of week specification (0-6, where 0=Sunday)
17
* @param {number|number[]|Range} [hour] - Hour specification (0-23)
18
* @param {number|number[]|Range} [minute] - Minute specification (0-59)
19
* @param {number|number[]|Range} [second] - Second specification (0-59, defaults to 0)
20
*/
21
function RecurrenceRule(year?, month?, date?, dayOfWeek?, hour?, minute?, second?);
22
23
class RecurrenceRule {
24
/** Year specification (4-digit year, null for any) */
25
year: number | number[] | Range | null;
26
/** Month specification (0-11, null for any) */
27
month: number | number[] | Range | null;
28
/** Day of month specification (1-31, null for any) */
29
date: number | number[] | Range | null;
30
/** Day of week specification (0-6, Sunday=0, null for any) */
31
dayOfWeek: number | number[] | Range | null;
32
/** Hour specification (0-23, null for any) */
33
hour: number | number[] | Range | null;
34
/** Minute specification (0-59, null for any) */
35
minute: number | number[] | Range | null;
36
/** Second specification (0-59, null for any) */
37
second: number | number[] | Range | null;
38
/** Whether this rule allows recurrence */
39
recurs: boolean;
40
/** Timezone identifier */
41
tz: string;
42
}
43
```
44
45
**Usage Examples:**
46
47
```javascript
48
const { RecurrenceRule, scheduleJob } = require('node-schedule');
49
50
// Every weekday at 9:30 AM
51
const rule1 = new RecurrenceRule();
52
rule1.dayOfWeek = [new Range(1, 5)]; // Monday to Friday
53
rule1.hour = 9;
54
rule1.minute = 30;
55
56
const job1 = scheduleJob(rule1, function() {
57
console.log('Weekday morning job');
58
});
59
60
// Every 15 minutes during business hours
61
const rule2 = new RecurrenceRule();
62
rule2.hour = [new Range(9, 17)]; // 9 AM to 5 PM
63
rule2.minute = [0, 15, 30, 45];
64
65
const job2 = scheduleJob(rule2, function() {
66
console.log('Business hours job');
67
});
68
69
// Last day of every month at midnight
70
const rule3 = new RecurrenceRule();
71
rule3.date = [28, 29, 30, 31]; // Will only fire on valid dates
72
rule3.hour = 0;
73
rule3.minute = 0;
74
75
const job3 = scheduleJob(rule3, function() {
76
console.log('Month-end job');
77
});
78
```
79
80
### RecurrenceRule Methods
81
82
Methods for validating and calculating recurrence rule behavior.
83
84
```javascript { .api }
85
/**
86
* Check if the recurrence rule configuration is valid
87
* @returns {boolean} True if rule is valid
88
*/
89
RecurrenceRule.prototype.isValid = function();
90
91
/**
92
* Calculate the next date that matches this recurrence rule
93
* @param {Date} [base] - Base date to calculate from (defaults to current time)
94
* @returns {Date|null} Next matching date or null if no future dates match
95
*/
96
RecurrenceRule.prototype.nextInvocationDate = function(base);
97
98
/**
99
* Internal method for calculating next invocation date (internal use)
100
* @param {Date} base - Base date to calculate from
101
* @returns {Date|null} Next matching date or null
102
*/
103
RecurrenceRule.prototype._nextInvocationDate = function(base);
104
```
105
106
### Range Class
107
108
Define ranges of values for use in recurrence rule specifications.
109
110
```javascript { .api }
111
/**
112
* Create a range for use in recurrence rules
113
* @param {number} [start=0] - Range start value (inclusive)
114
* @param {number} [end=60] - Range end value (inclusive)
115
* @param {number} [step=1] - Step between values in range
116
*/
117
function Range(start?, end?, step?);
118
119
class Range {
120
/** Range start value */
121
start: number;
122
/** Range end value */
123
end: number;
124
/** Step between values */
125
step: number;
126
}
127
```
128
129
**Usage Examples:**
130
131
```javascript
132
const { Range, RecurrenceRule, scheduleJob } = require('node-schedule');
133
134
// Every 5 minutes from 0 to 55
135
const every5Minutes = new Range(0, 55, 5); // 0, 5, 10, 15, ..., 55
136
137
const rule = new RecurrenceRule();
138
rule.minute = every5Minutes;
139
140
const job = scheduleJob(rule, function() {
141
console.log('Runs every 5 minutes');
142
});
143
144
// Business hours: 9 AM to 5 PM
145
const businessHours = new Range(9, 17);
146
rule.hour = businessHours;
147
148
// Weekdays only
149
const weekdays = new Range(1, 5); // Monday=1 to Friday=5
150
rule.dayOfWeek = weekdays;
151
```
152
153
### Range Methods
154
155
Methods for working with range objects.
156
157
```javascript { .api }
158
/**
159
* Check if a value falls within this range
160
* @param {number} val - Value to check
161
* @returns {boolean} True if the value is in the range
162
*/
163
Range.prototype.contains = function(val);
164
```
165
166
### Object Literal Recurrence
167
168
Alternative syntax using object literals instead of RecurrenceRule instances.
169
170
```javascript { .api }
171
/**
172
* Object-literal recurrence specification
173
* Each property can be a single value, array of values, or Range
174
*/
175
interface RecurrenceSpec {
176
/** Year specification */
177
year?: number | number[] | Range;
178
/** Month specification (0-11) */
179
month?: number | number[] | Range;
180
/** Day of month specification (1-31) */
181
date?: number | number[] | Range;
182
/** Day of week specification (0-6, Sunday=0) */
183
dayOfWeek?: number | number[] | Range;
184
/** Hour specification (0-23) */
185
hour?: number | number[] | Range;
186
/** Minute specification (0-59) */
187
minute?: number | number[] | Range;
188
/** Second specification (0-59) */
189
second?: number | number[] | Range;
190
}
191
```
192
193
**Usage Examples:**
194
195
```javascript
196
const schedule = require('node-schedule');
197
198
// Object literal syntax - every Tuesday and Thursday at 2:30 PM
199
const job1 = schedule.scheduleJob({
200
dayOfWeek: [2, 4], // Tuesday and Thursday
201
hour: 14,
202
minute: 30
203
}, function() {
204
console.log('Bi-weekly meeting reminder');
205
});
206
207
// Multiple values and ranges
208
const job2 = schedule.scheduleJob({
209
month: [0, 3, 6, 9], // Quarterly: Jan, Apr, Jul, Oct
210
date: 1, // First day of month
211
hour: 8,
212
minute: 0
213
}, function() {
214
console.log('Quarterly report');
215
});
216
217
// Complex scheduling with ranges
218
const { Range } = require('node-schedule');
219
220
const job3 = schedule.scheduleJob({
221
dayOfWeek: new Range(1, 5), // Weekdays
222
hour: [9, 12, 15], // 9 AM, noon, 3 PM
223
minute: [0, 30] // On the hour and half-hour
224
}, function() {
225
console.log('Regular check-in');
226
});
227
```
228
229
### Advanced Scheduling with Start/End Dates
230
231
Schedule jobs with recurrence rules and temporal boundaries.
232
233
```javascript { .api }
234
/**
235
* Schedule specification with temporal boundaries
236
*/
237
interface ScheduleSpec {
238
/** Recurrence rule or cron string */
239
rule: RecurrenceRule | string;
240
/** Start date for scheduling (job won't run before this) */
241
start?: Date;
242
/** End date for scheduling (job won't run after this) */
243
end?: Date;
244
/** Timezone for date calculations */
245
tz?: string;
246
}
247
```
248
249
**Usage Examples:**
250
251
```javascript
252
const schedule = require('node-schedule');
253
254
// Campaign that runs for a specific period
255
const campaignRule = new schedule.RecurrenceRule();
256
campaignRule.hour = [9, 12, 15, 18]; // 4 times daily
257
campaignRule.minute = 0;
258
259
const campaignJob = schedule.scheduleJob({
260
rule: campaignRule,
261
start: new Date('2024-01-01'),
262
end: new Date('2024-01-31'),
263
tz: 'America/New_York'
264
}, function() {
265
console.log('Campaign reminder');
266
});
267
268
// Event reminders leading up to a deadline
269
const reminderRule = new schedule.RecurrenceRule();
270
reminderRule.hour = 9;
271
reminderRule.minute = 0;
272
273
const reminderJob = schedule.scheduleJob({
274
rule: reminderRule,
275
start: new Date('2024-02-01'),
276
end: new Date('2024-02-14') // Valentine's Day
277
}, function() {
278
console.log('Valentine\'s Day reminder');
279
});
280
```
281
282
### Internal Functions
283
284
Low-level functions exposed primarily for testing and advanced use cases. These functions are part of the internal scheduling mechanism.
285
286
```javascript { .api }
287
/**
288
* Schedule an invocation for execution (internal use)
289
* @param {Invocation} invocation - Invocation to schedule
290
*/
291
function scheduleInvocation(invocation);
292
293
/**
294
* Cancel a pending invocation (internal use)
295
* @param {Invocation} invocation - Invocation to cancel
296
*/
297
function cancelInvocation(invocation);
298
299
/**
300
* Schedule the next recurrence of a recurring job (internal use)
301
* @param {RecurrenceRule} rule - Recurrence rule
302
* @param {Job} job - Job instance
303
* @param {Date} [prevDate] - Previous execution date
304
* @param {Date} [endDate] - Optional end date
305
* @returns {Invocation|null} Next invocation or null
306
*/
307
function scheduleNextRecurrence(rule, job, prevDate?, endDate?);
308
309
/**
310
* Comparator function for sorting invocations by fire date (internal use)
311
* @param {Invocation} a - First invocation
312
* @param {Invocation} b - Second invocation
313
* @returns {number} Comparison result for sorting
314
*/
315
function sorter(a, b);
316
317
/**
318
* Internal array of all scheduled invocations
319
* Used for internal scheduling management and testing
320
*/
321
const _invocations: Invocation[];
322
```
323
324
### Cron String Support
325
326
Node Schedule supports standard cron expressions with an optional seconds field.
327
328
**Cron Format:**
329
```
330
* * * * * *
331
┬ ┬ ┬ ┬ ┬ ┬
332
│ │ │ │ │ │
333
│ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun)
334
│ │ │ │ └───── month (1 - 12)
335
│ │ │ └────────── day of month (1 - 31)
336
│ │ └─────────────── hour (0 - 23)
337
│ └──────────────────── minute (0 - 59)
338
└───────────────────────── second (0 - 59, OPTIONAL)
339
```
340
341
**Usage Examples:**
342
343
```javascript
344
const schedule = require('node-schedule');
345
346
// Every 30 seconds
347
const job1 = schedule.scheduleJob('*/30 * * * * *', function() {
348
console.log('Every 30 seconds');
349
});
350
351
// At 2:30 PM every day
352
const job2 = schedule.scheduleJob('0 30 14 * * *', function() {
353
console.log('Daily at 2:30 PM');
354
});
355
356
// Every 5 minutes during business hours (9 AM - 5 PM) on weekdays
357
const job3 = schedule.scheduleJob('0 */5 9-17 * * 1-5', function() {
358
console.log('Business hours reminder');
359
});
360
361
// First day of every month at midnight
362
const job4 = schedule.scheduleJob('0 0 0 1 * *', function() {
363
console.log('Monthly job');
364
});
365
```
366
367
### Timezone Support
368
369
Handle scheduling across different timezones using timezone identifiers.
370
371
**Usage Examples:**
372
373
```javascript
374
const schedule = require('node-schedule');
375
376
// Schedule in specific timezone
377
const rule = new schedule.RecurrenceRule();
378
rule.hour = 9;
379
rule.minute = 0;
380
rule.tz = 'America/New_York';
381
382
const easternJob = schedule.scheduleJob(rule, function() {
383
console.log('9 AM Eastern Time job');
384
});
385
386
// Multiple timezone jobs
387
const timezones = ['America/New_York', 'America/Chicago', 'America/Denver', 'America/Los_Angeles'];
388
389
timezones.forEach(tz => {
390
const tzRule = new schedule.RecurrenceRule();
391
tzRule.hour = 8;
392
tzRule.minute = 0;
393
tzRule.tz = tz;
394
395
schedule.scheduleJob(`morning-${tz.split('/')[1]}`, tzRule, function() {
396
console.log(`Good morning from ${tz}!`);
397
});
398
});
399
```
400
401
### Rule Validation
402
403
Examples of valid and invalid rule configurations.
404
405
**Usage Examples:**
406
407
```javascript
408
const { RecurrenceRule, Range } = require('node-schedule');
409
410
// Valid rules
411
const validRule1 = new RecurrenceRule();
412
validRule1.month = new Range(0, 11); // All months
413
validRule1.hour = 12;
414
console.log('Valid:', validRule1.isValid()); // true
415
416
const validRule2 = new RecurrenceRule();
417
validRule2.dayOfWeek = [0, 6]; // Weekends
418
validRule2.hour = [10, 14, 18];
419
console.log('Valid:', validRule2.isValid()); // true
420
421
// Invalid rules (will return false for isValid())
422
const invalidRule1 = new RecurrenceRule();
423
invalidRule1.hour = 25; // Hours only go 0-23
424
console.log('Invalid hour:', invalidRule1.isValid()); // false
425
426
const invalidRule2 = new RecurrenceRule();
427
invalidRule2.minute = -5; // Minutes must be 0-59
428
console.log('Invalid minute:', invalidRule2.isValid()); // false
429
430
const invalidRule3 = new RecurrenceRule();
431
invalidRule3.month = 1; // February
432
invalidRule3.date = 30; // February never has 30 days
433
console.log('Invalid date:', invalidRule3.isValid()); // false
434
435
// Testing next invocation calculation
436
const testRule = new RecurrenceRule();
437
testRule.hour = 9;
438
testRule.minute = 0;
439
440
const nextRun = testRule.nextInvocationDate();
441
console.log('Next 9 AM:', nextRun);
442
443
// Rule that will never match (returns null)
444
const neverRule = new RecurrenceRule();
445
neverRule.year = 2020; // Past year
446
neverRule.month = 1;
447
neverRule.date = 1;
448
449
const neverDate = neverRule.nextInvocationDate();
450
console.log('Never runs:', neverDate); // null
451
```
452
453
### Error Handling
454
455
Common error scenarios and their handling:
456
457
**Usage Examples:**
458
459
```javascript
460
const schedule = require('node-schedule');
461
462
try {
463
// This will throw RangeError: Invalid number of arguments
464
const invalidJob = schedule.scheduleJob(function() {
465
console.log('Missing schedule spec');
466
});
467
} catch (error) {
468
console.error('Scheduling error:', error.message);
469
}
470
471
try {
472
// This will throw RangeError: The job method must be a function
473
const invalidJob = schedule.scheduleJob('0 * * * *', 'not a function');
474
} catch (error) {
475
console.error('Job method error:', error.message);
476
}
477
478
// Invalid cron expression handling
479
const badCronJob = schedule.scheduleJob('invalid cron', function() {
480
console.log('This will not be scheduled');
481
});
482
console.log('Bad cron job:', badCronJob); // null
483
484
// Rescheduling one-off jobs by name throws Error
485
const oneOffJob = schedule.scheduleJob('oneOff', new Date(Date.now() + 5000), function() {
486
console.log('One-off job');
487
});
488
489
try {
490
schedule.rescheduleJob('oneOff', new Date(Date.now() + 10000));
491
} catch (error) {
492
console.error('Reschedule error:', error.message); // Cannot reschedule one-off job by name
493
}
494
```