cron-parser
Advanced tools
Comparing version 2.3.1 to 2.4.0
@@ -5,3 +5,3 @@ { | ||
"description": "Node.js library for parsing crontab instructions", | ||
"version": "2.3.1", | ||
"version": "2.4.0", | ||
"keywords": ["cron", "crontab", "parser"], | ||
@@ -8,0 +8,0 @@ "dependencies": {}, |
@@ -41,2 +41,38 @@ 'use strict'; | ||
CronDate.prototype.subtractYear = function() { | ||
this._date.subtract(1, 'year'); | ||
}; | ||
CronDate.prototype.subtractMonth = function() { | ||
this._date.subtract(1, 'month').endOf('month'); | ||
}; | ||
CronDate.prototype.subtractDay = function() { | ||
this._date.subtract(1, 'day').endOf('day'); | ||
}; | ||
CronDate.prototype.subtractHour = function() { | ||
var prev = this.getTime(); | ||
this._date.subtract(1, 'hour').endOf('hour'); | ||
if (this.getTime() >= prev) { | ||
this._date.subtract(1, 'hour'); | ||
} | ||
}; | ||
CronDate.prototype.subtractMinute = function() { | ||
var prev = this.getTime(); | ||
this._date.subtract(1, 'minute').endOf('minute'); | ||
if (this.getTime() > prev) { | ||
this._date.subtract(1, 'hour'); | ||
} | ||
}; | ||
CronDate.prototype.subtractSecond = function() { | ||
var prev = this.getTime(); | ||
this._date.subtract(1, 'second').startOf('second'); | ||
if (this.getTime() > prev) { | ||
this._date.subtract(1, 'hour'); | ||
} | ||
}; | ||
CronDate.prototype.getDate = function() { | ||
@@ -43,0 +79,0 @@ return this._date.date(); |
@@ -25,2 +25,3 @@ 'use strict'; | ||
this._currentDate = new CronDate(options.currentDate, this._tz); | ||
this._startDate = options.startDate ? new CronDate(options.startDate, this._tz) : null; | ||
this._endDate = options.endDate ? new CronDate(options.endDate, this._tz) : null; | ||
@@ -341,3 +342,3 @@ this._fields = {}; | ||
/** | ||
* Find next matching schedule date | ||
* Find next or previous matching schedule date | ||
* | ||
@@ -347,3 +348,3 @@ * @return {CronDate} | ||
*/ | ||
CronExpression.prototype._findSchedule = function _findSchedule () { | ||
CronExpression.prototype._findSchedule = function _findSchedule (reverse) { | ||
@@ -387,2 +388,6 @@ /** | ||
// Whether to use backwards directionality when searching | ||
reverse = reverse || false; | ||
var dateMathVerb = reverse ? 'subtract' : 'add'; | ||
var method = function(name) { | ||
@@ -393,15 +398,17 @@ return !this._utc ? name : ('getUTC' + name.slice(3)); | ||
var currentDate = new CronDate(this._currentDate, this._tz); | ||
var startDate = this._startDate; | ||
var endDate = this._endDate; | ||
// TODO: Improve this part | ||
// Always increment second value when second part is present | ||
if (this._fields.second.length > 1 && !this._hasIterated) { | ||
currentDate.addSecond(); | ||
} | ||
// Find matching schedule | ||
var initial_ts = currentDate.getTime(); | ||
while (true) { | ||
// Validate timespan | ||
if (endDate && (endDate.getTime() - currentDate.getTime()) < 0) { | ||
throw new Error('Out of the timespan range'); | ||
if (reverse) { | ||
if (startDate && (currentDate.getTime() - startDate.getTime() < 0)) { | ||
throw new Error('Out of the timespan range'); | ||
} | ||
} else { | ||
if (endDate && (endDate.getTime() - currentDate.getTime()) < 0) { | ||
throw new Error('Out of the timespan range'); | ||
} | ||
} | ||
@@ -452,24 +459,24 @@ | ||
// Add day if select day not match with month (according to calendar) | ||
// Add or subtract day if select day not match with month (according to calendar) | ||
if (!dayOfMonthMatch && !dayOfWeekMatch) { | ||
currentDate.addDay(); | ||
currentDate[dateMathVerb + 'Day'](); | ||
continue; | ||
} | ||
// Add day if not day of month is set (and no match) and day of week is wildcard | ||
// Add or subtract day if not day of month is set (and no match) and day of week is wildcard | ||
if (!isDayOfMonthWildcardMatch && isDayOfWeekWildcardMatch && !dayOfMonthMatch) { | ||
currentDate.addDay(); | ||
currentDate[dateMathVerb + 'Day'](); | ||
continue; | ||
} | ||
// Add day if not day of week is set (and no match) and day of month is wildcard | ||
// Add or subtract day if not day of week is set (and no match) and day of month is wildcard | ||
if (isDayOfMonthWildcardMatch && !isDayOfWeekWildcardMatch && !dayOfWeekMatch) { | ||
currentDate.addDay(); | ||
currentDate[dateMathVerb + 'Day'](); | ||
continue; | ||
} | ||
// Add day if day of mont and week are non-wildcard values and both doesn't match | ||
// Add or subtract day if day of month and week are non-wildcard values and both doesn't match | ||
if (!(isDayOfMonthWildcardMatch && isDayOfWeekWildcardMatch) && | ||
!dayOfMonthMatch && !dayOfWeekMatch) { | ||
currentDate.addDay(); | ||
currentDate[dateMathVerb + 'Day'](); | ||
continue; | ||
@@ -480,3 +487,3 @@ } | ||
if (!matchSchedule(currentDate[method('getMonth')]() + 1, this._fields.month)) { | ||
currentDate.addMonth(); | ||
currentDate[dateMathVerb + 'Month'](); | ||
continue; | ||
@@ -489,18 +496,19 @@ } | ||
this._dstStart = null; | ||
this._applyTimezoneShift(currentDate, 'addHour'); | ||
this._applyTimezoneShift(currentDate, dateMathVerb + 'Hour'); | ||
continue; | ||
} else if (!matchSchedule(currentHour - 1, this._fields.hour)) { | ||
currentDate.addHour(); | ||
currentDate[dateMathVerb + 'Hour'](); | ||
continue; | ||
} | ||
} else if (this._dstEnd === currentHour) { | ||
this._dstEnd = null; | ||
this._applyTimezoneShift(currentDate, 'addHour'); | ||
continue; | ||
if (!reverse) { | ||
this._dstEnd = null; | ||
this._applyTimezoneShift(currentDate, 'addHour'); | ||
continue; | ||
} | ||
} | ||
// Match minute | ||
if (!matchSchedule(currentDate[method('getMinutes')](), this._fields.minute)) { | ||
this._applyTimezoneShift(currentDate, 'addMinute'); | ||
this._applyTimezoneShift(currentDate, dateMathVerb + 'Minute'); | ||
continue; | ||
@@ -511,16 +519,17 @@ } | ||
if (!matchSchedule(currentDate[method('getSeconds')](), this._fields.second)) { | ||
this._applyTimezoneShift(currentDate, 'addSecond'); | ||
this._applyTimezoneShift(currentDate, dateMathVerb + 'Second'); | ||
continue; | ||
} | ||
// Increase a second in case in the first iteration the currentDate was not | ||
// modified | ||
if (initial_ts === currentDate.getTime()) { | ||
this._applyTimezoneShift(currentDate, dateMathVerb + 'Second'); | ||
continue; | ||
} | ||
break; | ||
} | ||
// When internal date is not mutated, append one second as a padding | ||
var nextDate = new CronDate(currentDate, this._tz); | ||
if (this._currentDate !== currentDate) { | ||
nextDate.addSecond(); | ||
} | ||
this._currentDate = nextDate; | ||
this._currentDate = new CronDate(currentDate, this._tz); | ||
this._hasIterated = true; | ||
@@ -552,2 +561,22 @@ | ||
/** | ||
* Find previous suitable date | ||
* | ||
* @public | ||
* @return {CronDate|Object} | ||
*/ | ||
CronExpression.prototype.prev = function prev () { | ||
var schedule = this._findSchedule(true); | ||
// Try to return ES6 compatible iterator | ||
if (this._isIterator) { | ||
return { | ||
value: schedule, | ||
done: !this.hasPrev() | ||
}; | ||
} | ||
return schedule; | ||
}; | ||
/** | ||
* Check if next suitable date exists | ||
@@ -561,2 +590,3 @@ * | ||
var hasIterated = this._hasIterated; | ||
try { | ||
@@ -574,2 +604,23 @@ this._findSchedule(); | ||
/** | ||
* Check if previous suitable date exists | ||
* | ||
* @public | ||
* @return {Boolean} | ||
*/ | ||
CronExpression.prototype.hasPrev = function() { | ||
var current = this._currentDate; | ||
var hasIterated = this._hasIterated; | ||
try { | ||
this._findSchedule(true); | ||
return true; | ||
} catch (err) { | ||
return false; | ||
} finally { | ||
this._currentDate = current; | ||
this._hasIterated = hasIterated; | ||
} | ||
}; | ||
/** | ||
* Iterate over expression iterator | ||
@@ -585,14 +636,30 @@ * | ||
for (var i = 0, c = steps; i < c; i++) { | ||
try { | ||
var item = this.next(); | ||
dates.push(item); | ||
if (steps >= 0) { | ||
for (var i = 0, c = steps; i < c; i++) { | ||
try { | ||
var item = this.next(); | ||
dates.push(item); | ||
// Fire the callback | ||
if (callback) { | ||
callback(item, i); | ||
// Fire the callback | ||
if (callback) { | ||
callback(item, i); | ||
} | ||
} catch (err) { | ||
break; | ||
} | ||
} catch (err) { | ||
break; | ||
} | ||
} else { | ||
for (var i = 0, c = steps; i > c; i--) { | ||
try { | ||
var item = this.prev(); | ||
dates.push(item); | ||
// Fire the callback | ||
if (callback) { | ||
callback(item, i); | ||
} | ||
} catch (err) { | ||
break; | ||
} | ||
} | ||
} | ||
@@ -599,0 +666,0 @@ |
{ | ||
"name": "cron-parser", | ||
"version": "2.3.1", | ||
"version": "2.4.0", | ||
"description": "Node.js library for parsing crontab instructions", | ||
@@ -36,3 +36,4 @@ "main": "lib/parser.js", | ||
"Yasuhiroki <yasuhiroki.duck@gmail.com>", | ||
"Nicholas Clawson <nickclaw@gmail.com>" | ||
"Nicholas Clawson <nickclaw@gmail.com>", | ||
"Brendan Warkentin <faazshift@gmail.com>" | ||
], | ||
@@ -45,2 +46,3 @@ "license": "MIT", | ||
"devDependencies": { | ||
"sinon": "^1.17.7", | ||
"tap": "^0.5.0" | ||
@@ -47,0 +49,0 @@ }, |
@@ -45,2 +45,5 @@ cron-parser | ||
console.log('Date: ', interval.next().toString()); // Sat Dec 29 2012 00:44:00 GMT+0200 (EET) | ||
console.log('Date: ', interval.prev().toString()); // Sat Dec 29 2012 00:42:00 GMT+0200 (EET) | ||
console.log('Date: ', interval.prev().toString()); // Sat Dec 29 2012 00:40:00 GMT+0200 (EET) | ||
} catch (err) { | ||
@@ -47,0 +50,0 @@ console.log('Error: ' + err.message); |
@@ -356,2 +356,3 @@ var util = require('util'); | ||
currentDate: new CronDate('Wed, 26 Dec 2012 14:38:53'), | ||
startDate: new CronDate('Wed, 26 Dec 2012 12:40:00'), | ||
endDate: new CronDate('Wed, 26 Dec 2012 16:40:00') | ||
@@ -364,6 +365,12 @@ }; | ||
var dates = interval.iterate(10); | ||
t.equal(dates.length, 7, 'Dates count matches'); | ||
t.equal(dates.length, 7, 'Dates count matches for positive iteration'); | ||
interval.reset(); // Reset | ||
interval.reset(); | ||
var dates = interval.iterate(-10); | ||
t.equal(dates.length, 6, 'Dates count matches for negative iteration'); | ||
interval.reset(); | ||
// Forward iteration | ||
var next = interval.next(); | ||
@@ -403,2 +410,43 @@ t.equal(next.getHours(), 14, 'Hour matches'); | ||
} | ||
// TODO: Currently, encountering an out-of-range failure (as above) | ||
// still results in a new interval being set on the object. | ||
// Until/unless this is fixed, the below test will fail. | ||
// next = interval.prev(); | ||
// t.equal(next.getHours(), 16, 'Hour matches'); | ||
// t.equal(next.getMinutes(), 20, 'Minute matches'); | ||
interval.reset(); | ||
// Backward iteration | ||
var prev = interval.prev(); | ||
t.equal(prev.getHours(), 14, 'Hour matches'); | ||
t.equal(prev.getMinutes(), 20, 'Minute matches'); | ||
prev = interval.prev(); | ||
t.equal(prev.getHours(), 14, 'Hour matches'); | ||
t.equal(prev.getMinutes(), 0, 'Minute matches'); | ||
prev = interval.prev(); | ||
t.equal(prev.getHours(), 13, 'Hour matches'); | ||
t.equal(prev.getMinutes(), 40, 'Minute matches'); | ||
prev = interval.prev(); | ||
t.equal(prev.getHours(), 13, 'Hour matches'); | ||
t.equal(prev.getMinutes(), 20, 'Minute matches'); | ||
prev = interval.prev(); | ||
t.equal(prev.getHours(), 13, 'Hour matches'); | ||
t.equal(prev.getMinutes(), 0, 'Minute matches'); | ||
prev = interval.prev(); | ||
t.equal(prev.getHours(), 12, 'Hour matches'); | ||
t.equal(prev.getMinutes(), 40, 'Minute matches'); | ||
try { | ||
interval.prev(); | ||
t.ok(false, 'Should fail'); | ||
} catch (e) { | ||
t.ok(true, 'Failed as expected'); | ||
} | ||
} catch (err) { | ||
@@ -405,0 +453,0 @@ t.ifError(err, 'Interval parse error'); |
Sorry, the diff of this file is not supported yet
104906
22
1914
130
2