moment-biz
Version:
Handle business days & weekends over multiple years
64 lines (48 loc) • 2.27 kB
JavaScript
'use strict';
const moment = require('moment');
function addSubBuisnessDays(originalCall, direction, val, period, ...args) {
if (val < 0)
return this[direction === 'add' ? 'subtract' : 'add'](-val, period, ...args);
const old = moment(this)[direction === 'add' ? 'startOf' : 'endOf']('day');
// add week-ends
const weekends = this.localeData()._config.weekends || [0, 6];
const nbWeekends = Math.floor(val / (7 - weekends.length));
originalCall.call(this, val + nbWeekends * weekends.length, 'day');
// how many week-end days did we miss with the previous naive calculation?
const weekendAdjustment = [...Array(val % (7 - weekends.length)).keys()].reduce(
(acc, i) => acc + (weekends.indexOf((this.day() + (direction === 'add' ? -i + 7 : i)) % 7) >= 0),
0
);
// adjust last weekend days if needed
if (weekendAdjustment) {
originalCall.call(this, weekendAdjustment, 'day');
while (this.isWeekend())
originalCall.call(this, 1, 'day');
}
// take holidays into account
var dayBoundary = moment(this)[direction === 'add' ? 'endOf' : 'startOf']('day');
const addSubIfHolidayÎsValid = date => {
// if the holiday is not in the current period (or is on a weekend), ignore it
if (!date.isValid() || date.isWeekend() ||
direction === 'add' && (date <= old || date > dayBoundary) ||
direction === 'subtract' && (date > old || date <= dayBoundary))
return;
this[direction](1, 'businessday');
dayBoundary = moment(this)[direction === 'add' ? 'endOf' : 'startOf']('day');
};
for (let year = old.year(); year <= this.year(); ++year)
moment.getHolidays(year, this.locale()).forEach(addSubIfHolidayÎsValid);
return this;
}
const momentAdd = moment.fn.add;
moment.fn.add = function(val, period) {
if (period !== 'businessday' && period !== 'businessdays')
return momentAdd.call(this, ...arguments);
return addSubBuisnessDays.call(this, momentAdd, 'add', ...arguments);
};
const momentSubtract = moment.fn.subtract;
moment.fn.subtract = function(val, period) {
if (period !== 'businessday' && period !== 'businessdays')
return momentSubtract.call(this, ...arguments);
return addSubBuisnessDays.call(this, momentSubtract, 'subtract', ...arguments);
};