498 lines
14 KiB
JavaScript
498 lines
14 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.CronDate = exports.DAYS_IN_MONTH = exports.DateMathOp = exports.TimeUnit = void 0;
|
|
const luxon_1 = require("luxon");
|
|
var TimeUnit;
|
|
(function (TimeUnit) {
|
|
TimeUnit["Second"] = "Second";
|
|
TimeUnit["Minute"] = "Minute";
|
|
TimeUnit["Hour"] = "Hour";
|
|
TimeUnit["Day"] = "Day";
|
|
TimeUnit["Month"] = "Month";
|
|
TimeUnit["Year"] = "Year";
|
|
})(TimeUnit || (exports.TimeUnit = TimeUnit = {}));
|
|
var DateMathOp;
|
|
(function (DateMathOp) {
|
|
DateMathOp["Add"] = "Add";
|
|
DateMathOp["Subtract"] = "Subtract";
|
|
})(DateMathOp || (exports.DateMathOp = DateMathOp = {}));
|
|
exports.DAYS_IN_MONTH = Object.freeze([31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]);
|
|
/**
|
|
* CronDate class that wraps the Luxon DateTime object to provide
|
|
* a consistent API for working with dates and times in the context of cron.
|
|
*/
|
|
class CronDate {
|
|
#date;
|
|
#dstStart = null;
|
|
#dstEnd = null;
|
|
/**
|
|
* Maps the verb to the appropriate method
|
|
*/
|
|
#verbMap = {
|
|
add: {
|
|
[TimeUnit.Year]: this.addYear.bind(this),
|
|
[TimeUnit.Month]: this.addMonth.bind(this),
|
|
[TimeUnit.Day]: this.addDay.bind(this),
|
|
[TimeUnit.Hour]: this.addHour.bind(this),
|
|
[TimeUnit.Minute]: this.addMinute.bind(this),
|
|
[TimeUnit.Second]: this.addSecond.bind(this),
|
|
},
|
|
subtract: {
|
|
[TimeUnit.Year]: this.subtractYear.bind(this),
|
|
[TimeUnit.Month]: this.subtractMonth.bind(this),
|
|
[TimeUnit.Day]: this.subtractDay.bind(this),
|
|
[TimeUnit.Hour]: this.subtractHour.bind(this),
|
|
[TimeUnit.Minute]: this.subtractMinute.bind(this),
|
|
[TimeUnit.Second]: this.subtractSecond.bind(this),
|
|
},
|
|
};
|
|
/**
|
|
* Constructs a new CronDate instance.
|
|
* @param {CronDate | Date | number | string} [timestamp] - The timestamp to initialize the CronDate with.
|
|
* @param {string} [tz] - The timezone to use for the CronDate.
|
|
*/
|
|
constructor(timestamp, tz) {
|
|
const dateOpts = { zone: tz };
|
|
// Initialize the internal DateTime object based on the type of timestamp provided.
|
|
if (!timestamp) {
|
|
this.#date = luxon_1.DateTime.local();
|
|
}
|
|
else if (timestamp instanceof CronDate) {
|
|
this.#date = timestamp.#date;
|
|
this.#dstStart = timestamp.#dstStart;
|
|
this.#dstEnd = timestamp.#dstEnd;
|
|
}
|
|
else if (timestamp instanceof Date) {
|
|
this.#date = luxon_1.DateTime.fromJSDate(timestamp, dateOpts);
|
|
}
|
|
else if (typeof timestamp === 'number') {
|
|
this.#date = luxon_1.DateTime.fromMillis(timestamp, dateOpts);
|
|
}
|
|
else {
|
|
this.#date = luxon_1.DateTime.fromISO(timestamp, dateOpts);
|
|
this.#date.isValid || (this.#date = luxon_1.DateTime.fromRFC2822(timestamp, dateOpts));
|
|
this.#date.isValid || (this.#date = luxon_1.DateTime.fromSQL(timestamp, dateOpts));
|
|
this.#date.isValid || (this.#date = luxon_1.DateTime.fromFormat(timestamp, 'EEE, d MMM yyyy HH:mm:ss', dateOpts));
|
|
}
|
|
// Check for valid DateTime and throw an error if not valid.
|
|
if (!this.#date.isValid) {
|
|
throw new Error(`CronDate: unhandled timestamp: ${timestamp}`);
|
|
}
|
|
// Set the timezone if it is provided and different from the current zone.
|
|
if (tz && tz !== this.#date.zoneName) {
|
|
this.#date = this.#date.setZone(tz);
|
|
}
|
|
}
|
|
/**
|
|
* Determines if the given year is a leap year.
|
|
* @param {number} year - The year to check
|
|
* @returns {boolean} - True if the year is a leap year, false otherwise
|
|
* @private
|
|
*/
|
|
static #isLeapYear(year) {
|
|
return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
|
|
}
|
|
/**
|
|
* Returns daylight savings start time.
|
|
* @returns {number | null}
|
|
*/
|
|
get dstStart() {
|
|
return this.#dstStart;
|
|
}
|
|
/**
|
|
* Sets daylight savings start time.
|
|
* @param {number | null} value
|
|
*/
|
|
set dstStart(value) {
|
|
this.#dstStart = value;
|
|
}
|
|
/**
|
|
* Returns daylight savings end time.
|
|
* @returns {number | null}
|
|
*/
|
|
get dstEnd() {
|
|
return this.#dstEnd;
|
|
}
|
|
/**
|
|
* Sets daylight savings end time.
|
|
* @param {number | null} value
|
|
*/
|
|
set dstEnd(value) {
|
|
this.#dstEnd = value;
|
|
}
|
|
/**
|
|
* Adds one year to the current CronDate.
|
|
*/
|
|
addYear() {
|
|
this.#date = this.#date.plus({ years: 1 });
|
|
}
|
|
/**
|
|
* Adds one month to the current CronDate.
|
|
*/
|
|
addMonth() {
|
|
this.#date = this.#date.plus({ months: 1 }).startOf('month');
|
|
}
|
|
/**
|
|
* Adds one day to the current CronDate.
|
|
*/
|
|
addDay() {
|
|
this.#date = this.#date.plus({ days: 1 }).startOf('day');
|
|
}
|
|
/**
|
|
* Adds one hour to the current CronDate.
|
|
*/
|
|
addHour() {
|
|
this.#date = this.#date.plus({ hours: 1 }).startOf('hour');
|
|
}
|
|
/**
|
|
* Adds one minute to the current CronDate.
|
|
*/
|
|
addMinute() {
|
|
this.#date = this.#date.plus({ minutes: 1 }).startOf('minute');
|
|
}
|
|
/**
|
|
* Adds one second to the current CronDate.
|
|
*/
|
|
addSecond() {
|
|
this.#date = this.#date.plus({ seconds: 1 });
|
|
}
|
|
/**
|
|
* Subtracts one year from the current CronDate.
|
|
*/
|
|
subtractYear() {
|
|
this.#date = this.#date.minus({ years: 1 });
|
|
}
|
|
/**
|
|
* Subtracts one month from the current CronDate.
|
|
* If the month is 1, it will subtract one year instead.
|
|
*/
|
|
subtractMonth() {
|
|
this.#date = this.#date.minus({ months: 1 }).endOf('month').startOf('second');
|
|
}
|
|
/**
|
|
* Subtracts one day from the current CronDate.
|
|
* If the day is 1, it will subtract one month instead.
|
|
*/
|
|
subtractDay() {
|
|
this.#date = this.#date.minus({ days: 1 }).endOf('day').startOf('second');
|
|
}
|
|
/**
|
|
* Subtracts one hour from the current CronDate.
|
|
* If the hour is 0, it will subtract one day instead.
|
|
*/
|
|
subtractHour() {
|
|
this.#date = this.#date.minus({ hours: 1 }).endOf('hour').startOf('second');
|
|
}
|
|
/**
|
|
* Subtracts one minute from the current CronDate.
|
|
* If the minute is 0, it will subtract one hour instead.
|
|
*/
|
|
subtractMinute() {
|
|
this.#date = this.#date.minus({ minutes: 1 }).endOf('minute').startOf('second');
|
|
}
|
|
/**
|
|
* Subtracts one second from the current CronDate.
|
|
* If the second is 0, it will subtract one minute instead.
|
|
*/
|
|
subtractSecond() {
|
|
this.#date = this.#date.minus({ seconds: 1 });
|
|
}
|
|
/**
|
|
* Adds a unit of time to the current CronDate.
|
|
* @param {TimeUnit} unit
|
|
*/
|
|
addUnit(unit) {
|
|
this.#verbMap.add[unit]();
|
|
}
|
|
/**
|
|
* Subtracts a unit of time from the current CronDate.
|
|
* @param {TimeUnit} unit
|
|
*/
|
|
subtractUnit(unit) {
|
|
this.#verbMap.subtract[unit]();
|
|
}
|
|
/**
|
|
* Handles a math operation.
|
|
* @param {DateMathOp} verb - {'add' | 'subtract'}
|
|
* @param {TimeUnit} unit - {'year' | 'month' | 'day' | 'hour' | 'minute' | 'second'}
|
|
*/
|
|
invokeDateOperation(verb, unit) {
|
|
if (verb === DateMathOp.Add) {
|
|
this.addUnit(unit);
|
|
return;
|
|
}
|
|
if (verb === DateMathOp.Subtract) {
|
|
this.subtractUnit(unit);
|
|
return;
|
|
}
|
|
/* istanbul ignore next - this would only happen if an end user call the handleMathOp with an invalid verb */
|
|
throw new Error(`Invalid verb: ${verb}`);
|
|
}
|
|
/**
|
|
* Returns the day.
|
|
* @returns {number}
|
|
*/
|
|
getDate() {
|
|
return this.#date.day;
|
|
}
|
|
/**
|
|
* Returns the year.
|
|
* @returns {number}
|
|
*/
|
|
getFullYear() {
|
|
return this.#date.year;
|
|
}
|
|
/**
|
|
* Returns the day of the week.
|
|
* @returns {number}
|
|
*/
|
|
getDay() {
|
|
const weekday = this.#date.weekday;
|
|
return weekday === 7 ? 0 : weekday;
|
|
}
|
|
/**
|
|
* Returns the month.
|
|
* @returns {number}
|
|
*/
|
|
getMonth() {
|
|
return this.#date.month - 1;
|
|
}
|
|
/**
|
|
* Returns the hour.
|
|
* @returns {number}
|
|
*/
|
|
getHours() {
|
|
return this.#date.hour;
|
|
}
|
|
/**
|
|
* Returns the minutes.
|
|
* @returns {number}
|
|
*/
|
|
getMinutes() {
|
|
return this.#date.minute;
|
|
}
|
|
/**
|
|
* Returns the seconds.
|
|
* @returns {number}
|
|
*/
|
|
getSeconds() {
|
|
return this.#date.second;
|
|
}
|
|
/**
|
|
* Returns the milliseconds.
|
|
* @returns {number}
|
|
*/
|
|
getMilliseconds() {
|
|
return this.#date.millisecond;
|
|
}
|
|
/**
|
|
* Returns the time.
|
|
* @returns {number}
|
|
*/
|
|
getTime() {
|
|
return this.#date.valueOf();
|
|
}
|
|
/**
|
|
* Returns the UTC day.
|
|
* @returns {number}
|
|
*/
|
|
getUTCDate() {
|
|
return this.#getUTC().day;
|
|
}
|
|
/**
|
|
* Returns the UTC year.
|
|
* @returns {number}
|
|
*/
|
|
getUTCFullYear() {
|
|
return this.#getUTC().year;
|
|
}
|
|
/**
|
|
* Returns the UTC day of the week.
|
|
* @returns {number}
|
|
*/
|
|
getUTCDay() {
|
|
const weekday = this.#getUTC().weekday;
|
|
return weekday === 7 ? 0 : weekday;
|
|
}
|
|
/**
|
|
* Returns the UTC month.
|
|
* @returns {number}
|
|
*/
|
|
getUTCMonth() {
|
|
return this.#getUTC().month - 1;
|
|
}
|
|
/**
|
|
* Returns the UTC hour.
|
|
* @returns {number}
|
|
*/
|
|
getUTCHours() {
|
|
return this.#getUTC().hour;
|
|
}
|
|
/**
|
|
* Returns the UTC minutes.
|
|
* @returns {number}
|
|
*/
|
|
getUTCMinutes() {
|
|
return this.#getUTC().minute;
|
|
}
|
|
/**
|
|
* Returns the UTC seconds.
|
|
* @returns {number}
|
|
*/
|
|
getUTCSeconds() {
|
|
return this.#getUTC().second;
|
|
}
|
|
/**
|
|
* Returns the UTC milliseconds.
|
|
* @returns {string | null}
|
|
*/
|
|
toISOString() {
|
|
return this.#date.toUTC().toISO();
|
|
}
|
|
/**
|
|
* Returns the date as a JSON string.
|
|
* @returns {string | null}
|
|
*/
|
|
toJSON() {
|
|
return this.#date.toJSON();
|
|
}
|
|
/**
|
|
* Sets the day.
|
|
* @param d
|
|
*/
|
|
setDate(d) {
|
|
this.#date = this.#date.set({ day: d });
|
|
}
|
|
/**
|
|
* Sets the year.
|
|
* @param y
|
|
*/
|
|
setFullYear(y) {
|
|
this.#date = this.#date.set({ year: y });
|
|
}
|
|
/**
|
|
* Sets the day of the week.
|
|
* @param d
|
|
*/
|
|
setDay(d) {
|
|
this.#date = this.#date.set({ weekday: d });
|
|
}
|
|
/**
|
|
* Sets the month.
|
|
* @param m
|
|
*/
|
|
setMonth(m) {
|
|
this.#date = this.#date.set({ month: m + 1 });
|
|
}
|
|
/**
|
|
* Sets the hour.
|
|
* @param h
|
|
*/
|
|
setHours(h) {
|
|
this.#date = this.#date.set({ hour: h });
|
|
}
|
|
/**
|
|
* Sets the minutes.
|
|
* @param m
|
|
*/
|
|
setMinutes(m) {
|
|
this.#date = this.#date.set({ minute: m });
|
|
}
|
|
/**
|
|
* Sets the seconds.
|
|
* @param s
|
|
*/
|
|
setSeconds(s) {
|
|
this.#date = this.#date.set({ second: s });
|
|
}
|
|
/**
|
|
* Sets the milliseconds.
|
|
* @param s
|
|
*/
|
|
setMilliseconds(s) {
|
|
this.#date = this.#date.set({ millisecond: s });
|
|
}
|
|
/**
|
|
* Returns the date as a string.
|
|
* @returns {string}
|
|
*/
|
|
toString() {
|
|
return this.toDate().toString();
|
|
}
|
|
/**
|
|
* Returns the date as a Date object.
|
|
* @returns {Date}
|
|
*/
|
|
toDate() {
|
|
return this.#date.toJSDate();
|
|
}
|
|
/**
|
|
* Returns true if the day is the last day of the month.
|
|
* @returns {boolean}
|
|
*/
|
|
isLastDayOfMonth() {
|
|
const { day, month } = this.#date;
|
|
// Special handling for February in leap years
|
|
if (month === 2) {
|
|
const isLeap = CronDate.#isLeapYear(this.#date.year);
|
|
return day === exports.DAYS_IN_MONTH[month - 1] - (isLeap ? 0 : 1);
|
|
}
|
|
// For other months, check against the static map
|
|
return day === exports.DAYS_IN_MONTH[month - 1];
|
|
}
|
|
/**
|
|
* Returns true if the day is the last weekday of the month.
|
|
* @returns {boolean}
|
|
*/
|
|
isLastWeekdayOfMonth() {
|
|
const { day, month } = this.#date;
|
|
// Get the last day of the current month
|
|
let lastDay;
|
|
if (month === 2) {
|
|
// Special handling for February
|
|
lastDay = exports.DAYS_IN_MONTH[month - 1] - (CronDate.#isLeapYear(this.#date.year) ? 0 : 1);
|
|
}
|
|
else {
|
|
lastDay = exports.DAYS_IN_MONTH[month - 1];
|
|
}
|
|
// Check if the current day is within 7 days of the end of the month
|
|
return day > lastDay - 7;
|
|
}
|
|
/**
|
|
* Primarily for internal use.
|
|
* @param {DateMathOp} op - The operation to perform.
|
|
* @param {TimeUnit} unit - The unit of time to use.
|
|
* @param {number} [hoursLength] - The length of the hours. Required when unit is not month or day.
|
|
*/
|
|
applyDateOperation(op, unit, hoursLength) {
|
|
if (unit === TimeUnit.Month || unit === TimeUnit.Day) {
|
|
this.invokeDateOperation(op, unit);
|
|
return;
|
|
}
|
|
const previousHour = this.getHours();
|
|
this.invokeDateOperation(op, unit);
|
|
const currentHour = this.getHours();
|
|
const diff = currentHour - previousHour;
|
|
if (diff === 2) {
|
|
if (hoursLength !== 24) {
|
|
this.dstStart = currentHour;
|
|
}
|
|
}
|
|
else if (diff === 0 && this.getMinutes() === 0 && this.getSeconds() === 0) {
|
|
if (hoursLength !== 24) {
|
|
this.dstEnd = currentHour;
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Returns the UTC date.
|
|
* @private
|
|
* @returns {DateTime}
|
|
*/
|
|
#getUTC() {
|
|
return this.#date.toUTC();
|
|
}
|
|
}
|
|
exports.CronDate = CronDate;
|
|
exports.default = CronDate;
|