Created
January 21, 2019 09:20
-
-
Save chanakaDe/dc316d1488c179f41df1acbca8b1ce65 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Weekdays calculator | |
* @author Andrei Kondratev [[email protected]] | |
*/ | |
;if ( typeof require !== 'undefined' ) | |
{ | |
moment = require('moment'); | |
} | |
(function(moment) { | |
var week_day_array = []; | |
function WeekDayCalc (rangeStart,rangeEnd,weekdays,exclusions,inclusions,useIsoWeekday) { | |
this.rangeStart = moment(rangeStart); | |
this.rangeEnd = moment(rangeEnd); | |
this.exclusions = exclusions; | |
this.inclusions = inclusions; | |
this.useIsoWeekday = (useIsoWeekday==true); | |
if(this.rangeStart.isAfter(this.rangeEnd)) { | |
throw new WeekDayCalcException('rangeStart is after rangeEnd'); | |
} | |
this.weekdays = parseWeekdays(weekdays, this.useIsoWeekday); | |
} | |
WeekDayCalc.prototype.calculate = function() { | |
var weekDaysCount = 0; | |
var rangeStartWeekEnd = this.rangeStart.clone().endOf('week'); | |
var rangeEndWeekStart = this.rangeEnd.clone().startOf('week'); | |
if (rangeEndWeekStart.diff(rangeStartWeekEnd,'days')<30 || this.exclusions || this.inclusions) { | |
weekDaysCount = this.calculateIterative(this.rangeStart,this.rangeEnd,this.weekdays,this.exclusions, this.inclusions); | |
} else { | |
/* a little optimisation for longer time intervals - it works faster with intervals longer than one year */ | |
var wholeWeeksDiff = Math.round(rangeEndWeekStart.diff(rangeStartWeekEnd,'weeks',true)); | |
weekDaysCount += wholeWeeksDiff*this.weekdays.length; | |
weekDaysCount += this.calculateIterative(this.rangeStart,rangeStartWeekEnd,this.weekdays); | |
weekDaysCount += this.calculateIterative(rangeEndWeekStart,this.rangeEnd,this.weekdays); | |
} | |
// return weekDaysCount; | |
// return week_day_array; | |
return [weekDaysCount , week_day_array]; | |
}; | |
WeekDayCalc.prototype.calculateIterative = function(rangeStart,rangeEnd,weekdays,exclusions, inclusions) { | |
var weekDaysCount = 0, day = rangeStart.clone(); | |
var str_exclusions = parseSet(exclusions); | |
var str_inclusions = parseSet(inclusions); | |
while(day.valueOf()<=rangeEnd.valueOf()) { | |
var weekdayFunc = this.useIsoWeekday?'isoWeekday':'weekday'; | |
var dayString = day.format("YYYY-MM-DD"); | |
var included = str_inclusions.length != 0 && str_inclusions.indexOf(dayString)>=0; | |
if (included || ( (weekdays.indexOf(day[weekdayFunc]())>=0) && (str_exclusions.length==0 || str_exclusions.indexOf(dayString)<0) )) { | |
console.log("output : ",dayString); | |
week_day_array.push(dayString); | |
weekDaysCount++; | |
} | |
day.add(1, 'day'); | |
} | |
return weekDaysCount; | |
}; | |
Function.prototype.construct = function(aArgs) { | |
/*Monkey patching Function prototype to have construct method*/ | |
var fConstructor = this, fNewConstr = function() { fConstructor.apply(this, aArgs); }; | |
fNewConstr.prototype = fConstructor.prototype; | |
return new fNewConstr(); | |
}; | |
function WeekDayCalcException (message) { | |
this.message = message; | |
this.name = 'WeekDayCalcException'; | |
} | |
WeekDayCalcException.prototype = new Error; | |
WeekDayCalc.prototype.WeekDayCalcException = WeekDayCalcException; | |
function DaysSetConverter (rangeStart, weekdays, exclusions, inclusions, useIsoWeekday) { | |
this.rangeStart = moment(rangeStart); | |
this.useIsoWeekday = (useIsoWeekday==true); | |
this.exclusions = exclusions; | |
this.inclusions = inclusions; | |
this.weekdays = parseWeekdays(weekdays, this.useIsoWeekday); | |
} | |
/** | |
* Calculates the date of {workdays} from now excluding today | |
* @param daysToAdd | |
* @returns {Suite|*} | |
*/ | |
DaysSetConverter.prototype.calculate = function(daysToAdd) { | |
var daysLeft = daysToAdd; | |
var resultDate = this.rangeStart.clone(); | |
var str_exclusions = parseSet(this.exclusions); | |
var str_inclusions = parseSet(this.inclusions); | |
var weekdayFunc = this.useIsoWeekday?'isoWeekday':'weekday'; | |
if (daysLeft>=0){ | |
/* positive value - add days */ | |
while (daysLeft > 0) { | |
resultDate.add(1, 'day'); | |
var included = str_inclusions.length != 0 && str_inclusions.indexOf(resultDate.format("YYYY-MM-DD"))>=0; | |
if (included || ((this.weekdays.indexOf(resultDate[weekdayFunc]()) >= 0) && (str_exclusions.length == 0 || str_exclusions.indexOf(resultDate.format("YYYY-MM-DD")) < 0))) { | |
daysLeft--; | |
} | |
} | |
} else { | |
/* negative value - subtract days */ | |
while (daysLeft < 0) { | |
resultDate.subtract(1, 'day'); | |
var included = str_inclusions.length != 0 && str_inclusions.indexOf(resultDate.format("YYYY-MM-DD"))>=0; | |
if (included || ((this.weekdays.indexOf(resultDate[weekdayFunc]()) >= 0) && (str_exclusions.length == 0 || str_exclusions.indexOf(resultDate.format("YYYY-MM-DD")) < 0))) { | |
daysLeft++; | |
} | |
} | |
} | |
return resultDate; | |
}; | |
function DaysSetConverterException (message) { | |
this.message = message; | |
this.name = 'DaysSetConverterException'; | |
} | |
DaysSetConverterException.prototype = new Error; | |
DaysSetConverter.prototype.DaysSetConverterException = DaysSetConverterException; | |
var parseWeekdays = function(weekdays, useIsoWeekday) { | |
var validWeekdays = []; | |
if (!weekdays) { | |
throw new WeekDayCalcException('weekdays must be defined'); | |
} | |
if (weekdays.length > 7) { | |
throw new WeekDayCalcException("Weekdays array exceeding week length of 7 days"); | |
} | |
for (var i=0;i<weekdays.length;i++) { | |
var weekday = weekdays[i]; | |
if (useIsoWeekday) { | |
if (isNaN(weekday)) throw new WeekDayCalcException("isoWeekDayCalc accepts weekdays as numbers only, try using weekdayCalc if you need a locale aware behaviour"); | |
if (weekday<1 || weekday>7) throw new WeekDayCalcException("The weekday is out of 1 to 7 range"); | |
} else if(!isNaN(weekday)){ | |
if (weekday<0 || weekday>6) throw new WeekDayCalcException("The weekday is out of 0 to 6 range"); | |
} else { | |
weekday = moment().day(weekday).weekday(); | |
} | |
if (validWeekdays.indexOf(weekday)>=0) { | |
throw new WeekDayCalcException("Weekdays set contains duplicate weekday"); | |
} | |
validWeekdays.push(weekday); | |
} | |
return validWeekdays; | |
}; | |
var parseSet = function(set) { | |
var str_exclusions = []; | |
if (set) { | |
var i=0, l = set.length; | |
for (;i<l;i++) { | |
str_exclusions.push(moment(set[i]).format("YYYY-MM-DD")); | |
} | |
} | |
return str_exclusions; | |
}; | |
WeekDayCalc.calculateWeekdays = function(that, inArgs, useIsoWeekday) { | |
var rangeStart, rangeEnd, weekdays, exclusions, inclusions; | |
useIsoWeekday = useIsoWeekday?true:false; | |
switch (inArgs.length) { | |
case 5: | |
exclusions = inArgs[3]; | |
inclusions = inArgs[4]; | |
case 4: | |
exclusions = inArgs[3]; | |
/* Fall-through to three args */ | |
case 3: | |
rangeStart = moment(inArgs[0]).startOf('day'); | |
rangeEnd = moment(inArgs[1]).endOf('day'); | |
weekdays = inArgs[2]; | |
break; | |
case 2: | |
rangeStart = that; | |
rangeEnd = inArgs[0]; | |
weekdays = inArgs[1]; | |
break; | |
case 1: | |
var arg = inArgs[0]; | |
if (arg && arg.rangeEnd && arg.weekdays) { | |
rangeStart = arg.rangeStart ? moment(arg.rangeStart).startOf('day') : that; | |
rangeEnd = moment(arg.rangeEnd).endOf('day'); | |
weekdays = arg.weekdays; | |
exclusions = arg.exclusions; | |
inclusions = arg.inclusions; | |
} else { | |
rangeStart = that.clone().startOf('year'); | |
rangeEnd = that.clone().endOf('year'); | |
weekdays = arg; | |
} | |
break; | |
default: | |
new WeekDayCalcException('unexpected arguments length '+inArgs.length+'. Expecting 1 to 4 args'); | |
} | |
if(rangeStart.isAfter(rangeEnd)) { | |
var trueEnd = rangeStart.clone(); | |
rangeStart = rangeEnd.clone(); | |
rangeEnd = trueEnd; | |
} | |
var calc = WeekDayCalc.construct([rangeStart, rangeEnd, weekdays, exclusions, inclusions, useIsoWeekday]); | |
return calc.calculate(); | |
}; | |
DaysSetConverter.calculateDate = function(that, inArgs, useIsoWeekday) { | |
var days, exclusions, inclusions, weekdaysSet; | |
useIsoWeekday = useIsoWeekday?true:false; | |
var rangeStart = that; | |
switch (inArgs.length) { | |
case 4: | |
exclusions = inArgs[2]; | |
inclusions = inArgs[3]; | |
case 3: | |
exclusions = inArgs[2]; | |
/* Fall-through to two args*/ | |
case 2: | |
days = inArgs[0]; | |
weekdaysSet = inArgs[1]; | |
break; | |
case 1: | |
var arg = inArgs[0]; | |
if (arg && (arg.days!=undefined || arg.workdays!=undefined) ) { | |
if (arg.days!=undefined && arg.workdays!=undefined) throw new DaysSetConverterException("days and weekdays args should not be used together, because weekdays is an alias of days"); | |
days = arg.days?arg.days:arg.workdays; | |
weekdaysSet = arg.weekdays?arg.weekdays:[1,2,3,4,5]; | |
exclusions = arg.exclusions; | |
inclusions = arg.inclusions; | |
} else { | |
days = arg; | |
} | |
break; | |
default: | |
new DaysSetConverterException('unexpected arguments length '+inArgs.length+'. Expecting 1 to 3 args'); | |
} | |
var calc = DaysSetConverter.construct([that, weekdaysSet, exclusions, inclusions, useIsoWeekday]); | |
return calc.calculate(days); | |
}; | |
/** | |
* Calculate weekdays with locale aware weekdays | |
*/ | |
moment.fn.weekdayCalc = function(){ | |
return WeekDayCalc.calculateWeekdays(this, arguments); | |
}; | |
/** | |
* Calculate weekdays with moment#isoWeekdays function, where 1 is always monday and 7 is always Sunday | |
*/ | |
moment.fn.isoWeekdayCalc = function() { | |
return WeekDayCalc.calculateWeekdays(this, arguments, true); | |
}; | |
/** | |
* Calculates the date of {workdays} from now excluding today | |
* For example 4 workdays from Wed 19 Aug 2015 is a Tue 25 Aug 2015 | |
* workdays set is Mon-Fri, please use addSetWeekdays if you have a different set | |
*/ | |
moment.fn.addWorkdays = function(days, exclusions, inclusions) { | |
return DaysSetConverter.calculateDate(this, [days, [1,2,3,4,5], exclusions, inclusions]); | |
}; | |
/** | |
* Calculates how many calendar days within {workdays} | |
* For example 4 workdays from Wed 19 Aug 2015 is 6 calendar days | |
* workdays set is Mon-Fri, please use setWeekdaysToCalendarDays if you have a different set | |
*/ | |
moment.fn.workdaysToCalendarDays = function(days, exclusions, inclusions) { | |
var date = DaysSetConverter.calculateDate(this, [days, [1,2,3,4,5], exclusions, inclusions]); | |
return date.diff(this,'days'); | |
}; | |
moment.fn.addWeekdaysFromSet = function() { | |
return DaysSetConverter.calculateDate(this, arguments); | |
}; | |
moment.fn.weekdaysFromSetToCalendarDays = function() { | |
var date = DaysSetConverter.calculateDate(this, arguments); | |
return date.diff(this,'days'); | |
}; | |
moment.fn.isoAddWeekdaysFromSet = function() { | |
return DaysSetConverter.calculateDate(this, arguments, true); | |
}; | |
moment.fn.isoWeekdaysFromSetToCalendarDays = function() { | |
var date = DaysSetConverter.calculateDate(this, arguments, true); | |
return date.diff(this,'days'); | |
}; | |
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = WeekDayCalc : | |
typeof define === 'function' && define.amd ? define(WeekDayCalc) : | |
this.WeekDayCalc = WeekDayCalc; | |
})(moment); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment