@homebound/activesupport
Advanced tools
Comparing version 1.7.0 to 1.7.1
@@ -153,2 +153,86 @@ type KeysOfType<T, TProp> = { | ||
/** | ||
* @name addBusinessDays | ||
* @category Day Helpers | ||
* @summary Add the specified number of business days (mon - fri) to the given date. | ||
* | ||
* @description | ||
* Add the specified number of business days (mon - fri) to the given date, ignoring weekends. | ||
* | ||
* @param {Date|Number} date - the date to be changed | ||
* @param {Number} amount - the amount of business days to be added. Positive decimals will be rounded using `Math.floor`, decimals less than zero will be rounded using `Math.ceil`. | ||
* @param {Object} [options] - an object with options. | ||
* @param {Number[]} [options.businessDays=[1, 2, 3, 4, 5]] - the business days. default is Monday to Friday. | ||
* @param {Record<string, boolean>} [options.exceptions={}] - exceptions to the business days. Map of date string (with format "MM/DD/YY") to boolean. | ||
* @returns {Date} the new date with the business days added | ||
* @throws {TypeError} 2 arguments required | ||
* | ||
* @example | ||
* // Add 10 business days to 1 September 2014: | ||
* const result = addBusinessDays(new Date(2014, 8, 1), 10) | ||
* //=> Mon Sep 15 2014 00:00:00 (skipped weekend days) | ||
*/ | ||
declare function addBusinessDays(dirtyDate: Date | number, dirtyAmount: number, dirtyOptions?: { | ||
businessDays?: number[]; | ||
exceptions?: Record<string, boolean>; | ||
}): Date; | ||
/** | ||
* @name differenceInBusinessDays | ||
* @category Day Helpers | ||
* @summary Get the number of business days between the given dates. | ||
* | ||
* @description | ||
* Get the number of business day periods between the given dates. | ||
* Business days being days that arent in the weekend. | ||
* Like `differenceInCalendarDays`, the function removes the times from | ||
* the dates before calculating the difference. | ||
* | ||
* @param {Date|Number} dateLeft - the later date | ||
* @param {Date|Number} dateRight - the earlier date | ||
* @param {Object} [options] - an object with options. | ||
* @param {Number[]} [options.businessDays=[1, 2, 3, 4, 5]] - the business days. default is Monday to Friday. | ||
* @param {Record<string, boolean>} [options.exceptions={}] - exceptions to the business days. Map of date string (with format "MM/DD/YY") to boolean. | ||
* @returns {Number} the number of business days | ||
* @throws {TypeError} 2 arguments required | ||
* @throws {RangeError} businessDays cannot include numbers greater than 6 | ||
* | ||
* @example | ||
* // How many business days are between | ||
* // 10 January 2014 and 20 July 2014? | ||
* const result = differenceInBusinessDays( | ||
* new Date(2014, 6, 20), | ||
* new Date(2014, 0, 10) | ||
* ) | ||
* //=> 136 | ||
* | ||
* // How many business days are between | ||
* // 30 November 2021 and 1 November 2021? | ||
* const result = differenceInBusinessDays( | ||
* new Date(2021, 10, 30), | ||
* new Date(2021, 10, 1) | ||
* ) | ||
* //=> 21 | ||
* | ||
* // How many business days are between | ||
* // 1 November 2021 and 1 December 2021? | ||
* const result = differenceInBusinessDays( | ||
* new Date(2021, 10, 1), | ||
* new Date(2021, 11, 1) | ||
* ) | ||
* //=> -22 | ||
* | ||
* // How many business days are between | ||
* // 1 November 2021 and 1 November 2021 ? | ||
* const result = differenceInBusinessDays( | ||
* new Date(2021, 10, 1), | ||
* new Date(2021, 10, 1) | ||
* ) | ||
* //=> 0 | ||
*/ | ||
declare function differenceInBusinessDays(dirtyDateLeft: Date | number, dirtyDateRight: Date | number, dirtyOptions?: { | ||
businessDays?: number[]; | ||
exceptions?: Record<string, boolean>; | ||
}): number; | ||
declare global { | ||
@@ -173,2 +257,2 @@ interface Map<K, V> { | ||
export { KeysOfType, Sortable }; | ||
export { KeysOfType, Sortable, addBusinessDays, differenceInBusinessDays }; |
@@ -6,2 +6,6 @@ "use strict"; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __export = (target, all) => { | ||
for (var name in all) | ||
__defProp(target, name, { get: all[name], enumerable: true }); | ||
}; | ||
var __copyProps = (to, from, except, desc) => { | ||
@@ -19,2 +23,6 @@ if (from && typeof from === "object" || typeof from === "function") { | ||
var src_exports = {}; | ||
__export(src_exports, { | ||
addBusinessDays: () => addBusinessDays, | ||
differenceInBusinessDays: () => differenceInBusinessDays | ||
}); | ||
module.exports = __toCommonJS(src_exports); | ||
@@ -250,2 +258,108 @@ | ||
// src/businessDaysUtils.ts | ||
var import_date_fns = require("date-fns"); | ||
function addBusinessDays(dirtyDate, dirtyAmount, dirtyOptions) { | ||
const options = dirtyOptions || {}; | ||
const exceptions = options.exceptions || {}; | ||
const businessDays = options.businessDays || [1, 2, 3, 4, 5]; | ||
if (businessDays?.filter((number) => number > 6).length > 0) { | ||
throw new RangeError("business days must be between 0 and 6"); | ||
} | ||
const initialDate = (0, import_date_fns.toDate)(dirtyDate); | ||
const amount = dirtyAmount > 0 ? Math.floor(dirtyAmount) : Math.ceil(dirtyAmount); | ||
if (isNaN(amount)) | ||
return /* @__PURE__ */ new Date(NaN); | ||
if (initialDate.toString() === "Invalid Date") { | ||
return initialDate; | ||
} | ||
const findException = (date) => { | ||
return exceptions[(0, import_date_fns.format)(date, "MM/dd/yy")]; | ||
}; | ||
const isBusinessDay = (date) => businessDays.includes(date.getDay()); | ||
const isWorkingDay = (date) => { | ||
const isDateIncluded = options.exceptions ? findException(date) : void 0; | ||
if (isDateIncluded === false) | ||
return false; | ||
if (isDateIncluded === true || isBusinessDay(date)) { | ||
return true; | ||
} | ||
return false; | ||
}; | ||
const newDate = new Date(initialDate); | ||
const sign = amount < 0 ? -1 : 1; | ||
let dayCounter = Math.abs(amount); | ||
while (dayCounter > 0) { | ||
newDate.setDate(newDate.getDate() + sign); | ||
if (isWorkingDay(newDate)) | ||
dayCounter -= 1; | ||
} | ||
const reduceIfNonWorkingDay = (date) => { | ||
if (!isWorkingDay(date) && amount !== 0) { | ||
date.setDate(date.getDate() + sign); | ||
reduceIfNonWorkingDay(date); | ||
} | ||
}; | ||
reduceIfNonWorkingDay(newDate); | ||
newDate.setHours(initialDate.getHours()); | ||
return newDate; | ||
} | ||
function differenceInBusinessDays(dirtyDateLeft, dirtyDateRight, dirtyOptions) { | ||
const options = dirtyOptions || {}; | ||
const businessDays = options.businessDays || [1, 2, 3, 4, 5]; | ||
if (businessDays?.filter((number) => number > 6).length > 0) { | ||
throw new RangeError("business days must be between 0 and 6"); | ||
} | ||
const dateLeft = (0, import_date_fns.toDate)(dirtyDateLeft); | ||
const dateRight = (0, import_date_fns.toDate)(dirtyDateRight); | ||
const isHoliday = (date) => !businessDays.includes(date.getDay()); | ||
if (!(0, import_date_fns.isValid)(dateLeft) || !(0, import_date_fns.isValid)(dateRight)) | ||
return NaN; | ||
const calendarDifference = (0, import_date_fns.differenceInCalendarDays)(dateLeft, dateRight); | ||
const sign = calendarDifference < 0 ? -1 : 1; | ||
const isInDateBounds = (date) => { | ||
return sign > 0 ? (0, import_date_fns.isBefore)(date, dateLeft) && (0, import_date_fns.isAfter)(date, dateRight) : (0, import_date_fns.isAfter)(date, dateLeft) && (0, import_date_fns.isBefore)(date, dateRight); | ||
}; | ||
const weeks = Math.trunc(calendarDifference / 7); | ||
let result = weeks * businessDays.length; | ||
let newDateRight = (0, import_date_fns.addDays)(dateRight, weeks * 7); | ||
while (!(0, import_date_fns.isSameDay)(dateLeft, newDateRight)) { | ||
result += isHoliday(newDateRight) ? 0 : sign; | ||
newDateRight = (0, import_date_fns.addDays)(newDateRight, sign); | ||
} | ||
let exceptionCount = 0; | ||
if (options.exceptions) { | ||
const exceptionDates = Object.keys(options.exceptions); | ||
exceptionDates.forEach((e) => { | ||
const date = new Date(e); | ||
if (!(0, import_date_fns.isValid)(date)) | ||
return; | ||
if (isInDateBounds(date)) { | ||
if ( | ||
// if exception is true and date is not a business day | ||
options.exceptions[e] === true && !businessDays.includes(date.getDay()) | ||
) { | ||
exceptionCount += sign; | ||
} else if ( | ||
// if exception is false and date is a business day | ||
options.exceptions[e] === false && businessDays.includes(date.getDay()) | ||
) { | ||
exceptionCount -= sign; | ||
} | ||
} | ||
}); | ||
const leftAndRightExceptions = exceptionDates.filter((e) => { | ||
const date = new Date(e); | ||
return (0, import_date_fns.isSameDay)(date, dateLeft) || (0, import_date_fns.isSameDay)(date, dateRight); | ||
}); | ||
if (leftAndRightExceptions.length === 2) { | ||
if (leftAndRightExceptions.every((e) => options.exceptions[e] === true)) { | ||
exceptionCount++; | ||
} else if (leftAndRightExceptions.every((e) => options.exceptions[e] === false)) { | ||
exceptionCount--; | ||
} | ||
} | ||
} | ||
return result + exceptionCount; | ||
} | ||
// src/map.ts | ||
@@ -282,2 +396,7 @@ Map.prototype.getOrCreate = function(key, create) { | ||
}); | ||
// Annotate the CommonJS export names for ESM import in node: | ||
0 && (module.exports = { | ||
addBusinessDays, | ||
differenceInBusinessDays | ||
}); | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@homebound/activesupport", | ||
"version": "1.7.0", | ||
"version": "1.7.1", | ||
"main": "./dist/index.js", | ||
@@ -5,0 +5,0 @@ "module": "./dist/index.mjs", |
export * from "./array"; | ||
export * from "./businessDaysUtils"; | ||
export * from "./map"; | ||
export * from "./object"; | ||
export * from "./utils"; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
153132
1743