webservices/node_modules/cronosjs/dist-src/expression.js

180 lines
8.4 KiB
JavaScript

import { _parse } from './parser';
import { CronosDate, CronosTimezone } from './date';
import { flatMap } from './utils';
const hourinms = 60 * 60 * 1000;
const findFirstFrom = (from, list) => list.findIndex(n => n >= from);
export class CronosExpression {
constructor(cronString, seconds, minutes, hours, days, months, years) {
this.cronString = cronString;
this.seconds = seconds;
this.minutes = minutes;
this.hours = hours;
this.days = days;
this.months = months;
this.years = years;
this.skipRepeatedHour = true;
this.missingHour = 'insert';
this._warnings = null;
}
static parse(cronstring, options = {}) {
var _a;
const parsedFields = _parse(cronstring);
if (options.strict) {
let warnings = flatMap(parsedFields, field => field.warnings);
if (typeof options.strict === 'object') {
warnings = warnings
.filter(warning => !!options.strict[warning.type]);
}
if (warnings.length > 0) {
throw new Error(`Strict mode: Parsing failed with ${warnings.length} warnings`);
}
}
const expr = new CronosExpression(cronstring, parsedFields[0].values, parsedFields[1].values, parsedFields[2].values, parsedFields[3].values, parsedFields[4].values, parsedFields[5]);
expr.timezone = options.timezone instanceof CronosTimezone ? options.timezone :
(options.timezone !== undefined ? new CronosTimezone(options.timezone) : undefined);
expr.skipRepeatedHour = options.skipRepeatedHour !== undefined ? options.skipRepeatedHour : expr.skipRepeatedHour;
expr.missingHour = (_a = options.missingHour) !== null && _a !== void 0 ? _a : expr.missingHour;
return expr;
}
get warnings() {
if (!this._warnings) {
const parsedFields = _parse(this.cronString);
this._warnings = flatMap(parsedFields, field => field.warnings);
}
return this._warnings;
}
toString() {
var _a, _b;
const showTzOpts = !this.timezone || !!this.timezone.zoneName;
const timezone = Object.entries({
tz: (_b = (_a = this.timezone) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : 'Local',
skipRepeatedHour: showTzOpts && this.skipRepeatedHour.toString(),
missingHour: showTzOpts && this.missingHour,
}).map(([key, val]) => val && key + ': ' + val).filter(s => s).join(', ');
return `${this.cronString} (${timezone})`;
}
nextDate(afterDate = new Date()) {
var _a;
const fromCronosDate = CronosDate.fromDate(afterDate, this.timezone);
if (((_a = this.timezone) === null || _a === void 0 ? void 0 : _a.fixedOffset) !== undefined) {
return this._next(fromCronosDate).date;
}
const fromTimestamp = afterDate.getTime(), fromLocalTimestamp = fromCronosDate['toUTCTimestamp'](), prevHourLocalTimestamp = CronosDate.fromDate(new Date(fromTimestamp - hourinms), this.timezone)['toUTCTimestamp'](), nextHourLocalTimestamp = CronosDate.fromDate(new Date(fromTimestamp + hourinms), this.timezone)['toUTCTimestamp'](), nextHourRepeated = nextHourLocalTimestamp - fromLocalTimestamp === 0, thisHourRepeated = fromLocalTimestamp - prevHourLocalTimestamp === 0, thisHourMissing = fromLocalTimestamp - prevHourLocalTimestamp === hourinms * 2;
if (this.skipRepeatedHour && thisHourRepeated) {
return this._next(fromCronosDate.copyWith({ minute: 59, second: 60 }), false).date;
}
if (this.missingHour === 'offset' && thisHourMissing) {
const nextDate = this._next(fromCronosDate.copyWith({ hour: fromCronosDate.hour - 1 })).date;
if (!nextDate || nextDate.getTime() > fromTimestamp)
return nextDate;
}
let { date: nextDate, cronosDate: nextCronosDate } = this._next(fromCronosDate);
if (this.missingHour !== 'offset' && nextCronosDate && nextDate) {
const nextDateNextHourTimestamp = nextCronosDate.copyWith({ hour: nextCronosDate.hour + 1 }).toDate(this.timezone).getTime();
if (nextDateNextHourTimestamp === nextDate.getTime()) {
if (this.missingHour === 'insert') {
return nextCronosDate.copyWith({ minute: 0, second: 0 }).toDate(this.timezone);
}
// this.missingHour === 'skip'
return this._next(nextCronosDate.copyWith({ minute: 59, second: 59 })).date;
}
}
if (!this.skipRepeatedHour) {
if (nextHourRepeated && (!nextDate || (nextDate.getTime() > fromTimestamp + hourinms))) {
nextDate = this._next(fromCronosDate.copyWith({ minute: 0, second: 0 }), false).date;
}
if (nextDate && nextDate < afterDate) {
nextDate = new Date(nextDate.getTime() + hourinms);
}
}
return nextDate;
}
_next(date, after = true) {
const nextDate = this._nextYear(after ? date.copyWith({ second: date.second + 1 }) : date);
return {
cronosDate: nextDate,
date: nextDate ? nextDate.toDate(this.timezone) : null
};
}
nextNDates(afterDate = new Date(), n = 5) {
const dates = [];
let lastDate = afterDate;
for (let i = 0; i < n; i++) {
const date = this.nextDate(lastDate);
if (!date)
break;
lastDate = date;
dates.push(date);
}
return dates;
}
_nextYear(fromDate) {
let year = fromDate.year;
let nextDate = null;
while (!nextDate) {
year = this.years.nextYear(year);
if (year === null)
return null;
nextDate = this._nextMonth((year === fromDate.year) ? fromDate : new CronosDate(year));
year++;
}
return nextDate;
}
_nextMonth(fromDate) {
let nextMonthIndex = findFirstFrom(fromDate.month, this.months);
let nextDate = null;
while (!nextDate) {
const nextMonth = this.months[nextMonthIndex];
if (nextMonth === undefined)
return null;
nextDate = this._nextDay((nextMonth === fromDate.month) ? fromDate : new CronosDate(fromDate.year, nextMonth));
nextMonthIndex++;
}
return nextDate;
}
_nextDay(fromDate) {
const days = this.days.getDays(fromDate.year, fromDate.month);
let nextDayIndex = findFirstFrom(fromDate.day, days);
let nextDate = null;
while (!nextDate) {
const nextDay = days[nextDayIndex];
if (nextDay === undefined)
return null;
nextDate = this._nextHour((nextDay === fromDate.day) ? fromDate : new CronosDate(fromDate.year, fromDate.month, nextDay));
nextDayIndex++;
}
return nextDate;
}
_nextHour(fromDate) {
let nextHourIndex = findFirstFrom(fromDate.hour, this.hours);
let nextDate = null;
while (!nextDate) {
const nextHour = this.hours[nextHourIndex];
if (nextHour === undefined)
return null;
nextDate = this._nextMinute((nextHour === fromDate.hour) ? fromDate :
new CronosDate(fromDate.year, fromDate.month, fromDate.day, nextHour));
nextHourIndex++;
}
return nextDate;
}
_nextMinute(fromDate) {
let nextMinuteIndex = findFirstFrom(fromDate.minute, this.minutes);
let nextDate = null;
while (!nextDate) {
const nextMinute = this.minutes[nextMinuteIndex];
if (nextMinute === undefined)
return null;
nextDate = this._nextSecond((nextMinute === fromDate.minute) ? fromDate :
new CronosDate(fromDate.year, fromDate.month, fromDate.day, fromDate.hour, nextMinute));
nextMinuteIndex++;
}
return nextDate;
}
_nextSecond(fromDate) {
const nextSecondIndex = findFirstFrom(fromDate.second, this.seconds), nextSecond = this.seconds[nextSecondIndex];
if (nextSecond === undefined)
return null;
return fromDate.copyWith({ second: nextSecond });
}
}