Skip to content

Commit

Permalink
feat: add functions for overlapping dates
Browse files Browse the repository at this point in the history
- add functions that find overlapping & non overlapping dates
- add test code
- update version to 1.1.0
  • Loading branch information
hkc321 committed Apr 20, 2024
1 parent ab2c0f6 commit ca18edc
Show file tree
Hide file tree
Showing 5 changed files with 289 additions and 8 deletions.
151 changes: 150 additions & 1 deletion __test__/index.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
const {DateRangeCheckerError, isEndDateInRange, isInRange, isStartDateAndEndDateIncludeRange, isStartDateAndEndDateInRange, isStartDateInRange} = require("../src")
const {
DateRangeCheckerError,
isEndDateInRange,
isInRange,
isStartDateAndEndDateIncludeRange,
isStartDateAndEndDateInRange,
isStartDateInRange,
findOverlappingDates,
findNonOverlappingDates
} = require("../src")

describe('checkDateRangeFormat', () => {
test('Throws error if dateRange is undefined', () => {
Expand Down Expand Up @@ -132,3 +141,143 @@ describe('isStartDateAndEndDateIncludeRange', () => {
expect(result).toBe(false)
})
})

describe('findOverlappingDates', () => {
test('returns empty array when date ranges do not overlap', () => {
const result = findOverlappingDates(
{ startDate: new Date('2022-01-01'), endDate: new Date('2023-12-31') },
{ startDate: new Date('2024-01-01'), endDate: new Date('2024-11-01') }
)
expect(result).toEqual([]);
})

test('If there are overlapping dates, those dates are returned.', () => {
const referenceDateRange = { startDate: new Date('2022-01-01'), endDate: new Date('2022-01-15') };
const comparisonDateRange = { startDate: new Date('2022-01-05'), endDate: new Date('2022-01-20') };

const result = findOverlappingDates(referenceDateRange, comparisonDateRange);

expect(result).toEqual([
new Date('2022-01-05'),
new Date('2022-01-06'),
new Date('2022-01-07'),
new Date('2022-01-08'),
new Date('2022-01-09'),
new Date('2022-01-10'),
new Date('2022-01-11'),
new Date('2022-01-12'),
new Date('2022-01-13'),
new Date('2022-01-14'),
new Date('2022-01-15'),
]);
});

test('returns overlapping dates when one range is completely within the other', () => {
const referenceDateRange = { startDate: new Date('2022-01-05'), endDate: new Date('2022-01-10') };
const comparisonDateRange = { startDate: new Date('2022-01-01'), endDate: new Date('2022-01-15') };

const result = findOverlappingDates(referenceDateRange, comparisonDateRange);

expect(result).toEqual([
new Date('2022-01-05'),
new Date('2022-01-06'),
new Date('2022-01-07'),
new Date('2022-01-08'),
new Date('2022-01-09'),
new Date('2022-01-10')
]);
});

test('returns overlapping dates when date ranges are identical', () => {
const referenceDateRange = { startDate: new Date('2022-01-05'), endDate: new Date('2022-01-15') };
const comparisonDateRange = { startDate: new Date('2022-01-05'), endDate: new Date('2022-01-15') };

const result = findOverlappingDates(referenceDateRange, comparisonDateRange);

expect(result).toEqual([
new Date('2022-01-05'),
new Date('2022-01-06'),
new Date('2022-01-07'),
new Date('2022-01-08'),
new Date('2022-01-09'),
new Date('2022-01-10'),
new Date('2022-01-11'),
new Date('2022-01-12'),
new Date('2022-01-13'),
new Date('2022-01-14'),
new Date('2022-01-15')
]);
});
})

describe('findNonOverlappingDates', () => {
test('returns merging two date ranges when there are no overlapping dates', () => {
const referenceDateRange = { startDate: new Date('2022-01-01'), endDate: new Date('2022-01-10') };
const comparisonDateRange = { startDate: new Date('2022-01-11'), endDate: new Date('2022-01-15') };

const result = findNonOverlappingDates(referenceDateRange, comparisonDateRange);

expect(result).toEqual([
new Date('2022-01-01'),
new Date('2022-01-02'),
new Date('2022-01-03'),
new Date('2022-01-04'),
new Date('2022-01-05'),
new Date('2022-01-06'),
new Date('2022-01-07'),
new Date('2022-01-08'),
new Date('2022-01-09'),
new Date('2022-01-10'),
new Date('2022-01-11'),
new Date('2022-01-12'),
new Date('2022-01-13'),
new Date('2022-01-14'),
new Date('2022-01-15')
]);
})

test('returns empty array when both date ranges are same', () => {
const referenceDateRange = { startDate: new Date('2022-01-01'), endDate: new Date('2022-01-10') };
const comparisonDateRange = { startDate: new Date('2022-01-01'), endDate: new Date('2022-01-10') };

const result = findNonOverlappingDates(referenceDateRange, comparisonDateRange);

expect(result).toEqual([]);
})

test('returns nonOverlapping dates', () => {
const referenceDateRange = { startDate: new Date('2022-01-01'), endDate: new Date('2022-01-10') };
const comparisonDateRange = { startDate: new Date('2022-01-05'), endDate: new Date('2022-01-15') };

const result = findNonOverlappingDates(referenceDateRange, comparisonDateRange);

expect(result).toEqual([
new Date('2022-01-01'),
new Date('2022-01-02'),
new Date('2022-01-03'),
new Date('2022-01-04'),
new Date('2022-01-11'),
new Date('2022-01-12'),
new Date('2022-01-13'),
new Date('2022-01-14'),
new Date('2022-01-15')
]);

const referenceDateRangeReverse = { startDate: new Date('2022-01-05'), endDate: new Date('2022-01-15') };
const comparisonDateRangeReverse = { startDate: new Date('2022-01-01'), endDate: new Date('2022-01-10') };

const resultReverse = findNonOverlappingDates(referenceDateRangeReverse, comparisonDateRangeReverse);

expect(resultReverse).toEqual([
new Date('2022-01-01'),
new Date('2022-01-02'),
new Date('2022-01-03'),
new Date('2022-01-04'),
new Date('2022-01-11'),
new Date('2022-01-12'),
new Date('2022-01-13'),
new Date('2022-01-14'),
new Date('2022-01-15')
]);
})
})
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "date-range-checker",
"version": "1.0.4",
"version": "1.1.0",
"description": "A utility library for comparing date ranges",
"main": "dist/cjs/index.js",
"module": "dist/mjs/index.js",
Expand Down
122 changes: 118 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
interface DateRange {
startDate: Date;
endDate: Date;
}
import { DateRange } from "./type/type";
import { findDateRangeEachDates } from "./util";

class DateRangeCheckerError extends Error {
constructor(message: string) {
Expand Down Expand Up @@ -181,6 +179,120 @@ function isStartDateAndEndDateIncludeRange(referenceDateRange: DateRange, compar
);
}

/**
* @name findoverlappingDates
* @category Date Range Helpers
* @summary Finds overlapping dates between two date ranges.
*
* @description
* This function returns an array of dates that overlap between the given reference date range and comparison date range.
* If there is no overlap, an empty array is returned.
* Throws an error if the date range format is incorrect.
*
* @param {DateRange} referenceDateRange - The reference date range.
* @param {DateRange} comparisonDateRange - The comparison date range.
* @returns {Date[]} An array of overlapping dates found within the overlapping period of the two date ranges.
* @throws {DateRangeCheckerError} Throws an error if the date range format is incorrect.
*
* @example
* const overlappingDates = findOverlappingDates(
* { startDate: new Date('2022-01-01'), endDate: new Date('2022-01-10') },
* { startDate: new Date('2022-01-05'), endDate: new Date('2022-01-15') }
* );
* //=> [
* // new Date('2022-01-05'),
* // new Date('2022-01-06'),
* // new Date('2022-01-07'),
* // new Date('2022-01-08'),
* // new Date('2022-01-09'),
* // new Date('2022-01-10')
* // ]
*/
function findOverlappingDates(referenceDateRange: DateRange, comparisonDateRange: DateRange): Date[] {
checkDateRangeFormat(referenceDateRange);
checkDateRangeFormat(comparisonDateRange);

if (!isInRange(referenceDateRange, comparisonDateRange)) {
return [];
}

const startDate = referenceDateRange.startDate.getTime() > comparisonDateRange.startDate.getTime() ? new Date(referenceDateRange.startDate) : new Date(comparisonDateRange.startDate);
const endDate = referenceDateRange.endDate.getTime() < comparisonDateRange.endDate.getTime() ? new Date(referenceDateRange.endDate) : new Date(comparisonDateRange.endDate);

return [
...findDateRangeEachDates({startDate, endDate})
]
}

/**
* @name findNonOverlappingDates
* @category Date Range Helpers
* @summary Finds non overlapping dates between two date ranges.
*
* @description
* This function returns an array of dates that non overlapping between the given reference date range and comparison date range.
* If two date ranges are same, return empty array.
* Throws an error if the date range format is incorrect.
*
* @param {DateRange} referenceDateRange - The reference date range.
* @param {DateRange} comparisonDateRange - The comparison date range.
* @returns {Date[]} An array of overlapping dates found within the overlapping period of the two date ranges.
* @throws {DateRangeCheckerError} Throws an error if the date range format is incorrect.
*
* @example
* const nonOverlappingDates = findNonOverlappingDates(
* { startDate: new Date('2022-01-01'), endDate: new Date('2022-01-10') },
* { startDate: new Date('2022-01-05'), endDate: new Date('2022-01-15') }
* );
* //=> [
* // new Date('2022-01-01'),
* // new Date('2022-01-02'),
* // new Date('2022-01-03'),
* // new Date('2022-01-04'),
* // new Date('2022-01-11'),
* // new Date('2022-01-12')
* // new Date('2022-01-13')
* // new Date('2022-01-14')
* // new Date('2022-01-15')
* // ]
*/
function findNonOverlappingDates(referenceDateRange: DateRange, comparisonDateRange: DateRange): Date[] {
checkDateRangeFormat(referenceDateRange);
checkDateRangeFormat(comparisonDateRange);

if (!isInRange(referenceDateRange, comparisonDateRange)) {
return [
...findDateRangeEachDates({
startDate: referenceDateRange.startDate,
endDate: referenceDateRange.endDate
}),
...findDateRangeEachDates({
startDate: comparisonDateRange.startDate,
endDate: comparisonDateRange.endDate
})
];
}

const firstStartDate = referenceDateRange.startDate.getTime() < comparisonDateRange.startDate.getTime() ? new Date(referenceDateRange.startDate) : new Date(comparisonDateRange.startDate);
const firstEndDate = firstStartDate.getTime() === referenceDateRange.startDate.getTime() ? new Date(comparisonDateRange.startDate) : new Date(referenceDateRange.startDate);
firstEndDate.setDate(firstEndDate.getDate() - 1);

const secondStartDate = referenceDateRange.endDate.getTime() < comparisonDateRange.endDate.getTime() ? new Date(referenceDateRange.endDate) : new Date(comparisonDateRange.endDate);
const secondEndDate = secondStartDate.getTime() == referenceDateRange.endDate.getTime() ? new Date(comparisonDateRange.endDate) : new Date(referenceDateRange.endDate);
secondStartDate.setDate(secondStartDate.getDate() + 1)

return [
...findDateRangeEachDates({
startDate: firstStartDate,
endDate: firstEndDate
}),
...findDateRangeEachDates({
startDate: secondStartDate,
endDate: secondEndDate
})
]
}

/**
* @name checkDateRangeFormat
* @category Date Range Helpers
Expand Down Expand Up @@ -220,5 +332,7 @@ export {
isEndDateInRange,
isStartDateAndEndDateInRange,
isStartDateAndEndDateIncludeRange,
findOverlappingDates,
findNonOverlappingDates,
DateRangeCheckerError
}
18 changes: 18 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { DateRange } from "./type/type";


function findDateRangeEachDates(dateRange: DateRange): Date[] {
const result: Date[] = [];
let currentDate = new Date(dateRange.startDate);

while (currentDate.getTime() <= dateRange.endDate.getTime()) {
result.push(new Date(currentDate));
currentDate.setDate(currentDate.getDate() + 1);
}

return result;
}

export {
findDateRangeEachDates
}

0 comments on commit ca18edc

Please sign in to comment.