diff --git a/CHANGELOG.md b/CHANGELOG.md
index a993a6a..7607cd8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,18 @@
# @sgx4u/date-time-utils - Changelog
+## 2.3.0
+
+### Minor Release
+
+- Added function - `getNextOccurrence`
+- Bug fix in isValidDate where it should stop further checks when valid date is already confirmed
+
+## 2.2.1
+
+### Documentation
+
+- Updated documentation
+
## 2.2.0
### Minor Release
diff --git a/README.md b/README.md
index 0f7a4c9..2e1e2da 100644
--- a/README.md
+++ b/README.md
@@ -38,6 +38,7 @@
- [`addSubtractTime`](https://github.com/sgx4u/sgx4u-date-time-utils/blob/production/src/add-subtract-time/add-subtract-time.md) ‐ Add/Subtract time value from a given time and get the new value in different formats
- [`isValidDate`](https://github.com/sgx4u/sgx4u-date-time-utils/blob/production/src/is-valid-date/is-valid-date.md) ‐ Check if the given date is valid or not
- [`isLeapYear`](https://github.com/sgx4u/sgx4u-date-time-utils/blob/production/src/is-leap-year/is-leap-year.md) ‐ Check if the given year is a leap year
+- [`getNextOccurrence`](https://github.com/sgx4u/sgx4u-date-time-utils/blob/production/src/get-next-occurrence/get-next-occurrence.md) ‐ Find the next occurrence of the given day
diff --git a/package.json b/package.json
index 0447f1d..cef1419 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@sgx4u/date-time-utils",
- "version": "2.2.1",
+ "version": "2.3.0",
"private": false,
"description": "A date-time utility library",
"keywords": [
diff --git a/src/get-next-occurrence/get-next-occurrence.md b/src/get-next-occurrence/get-next-occurrence.md
new file mode 100644
index 0000000..3da0460
--- /dev/null
+++ b/src/get-next-occurrence/get-next-occurrence.md
@@ -0,0 +1,31 @@
+## `getNextOccurrence`
+
+Find the next occurrence of the given day.
+
+## Usage
+
+```tsx
+import { getNextOccurrence } from '@sgx4u/date-time-utils';
+
+const Demo = () => {
+ const nextSunday = getNextOccurrence('Sunday');
+ return
Next Sunday: {nextSunday}
; +}; +``` + +## Reference + +```ts +getNextOccurrence(day, startDate): string; +``` + +### Props + +- `day` The day to find the next occurrence of, `type`: 'Sunday' | 'Monday' | 'Tuesday' | 'Wednesday' | 'Thursday' | 'Friday' | 'Saturday' +- `startDate` The date to start checking from, `type`: Date | string | number, `optional` + +### Example + +- `getNextOccurrence('Sunday')` - With no start date mentioned it will default to the current date, so lets say current date is 10th Jan 2025. Result - 'Sun, 12 Jan 2025 00:00:00 GMT' +- `getNextOccurrence('Sunday', '2025-01-20T00:00:00.000Z')` - 'Sun, 26 Jan 2025 00:00:00 GMT' +- `getNextOccurrence('Sunday', 'ABC')` - 'Invalid date' diff --git a/src/get-next-occurrence/get-next-occurrence.test.ts b/src/get-next-occurrence/get-next-occurrence.test.ts new file mode 100644 index 0000000..29a4e20 --- /dev/null +++ b/src/get-next-occurrence/get-next-occurrence.test.ts @@ -0,0 +1,30 @@ +import { describe, expect, test } from '@jest/globals'; + +import { getNextOccurrence } from './get-next-occurrence'; + +describe('getNextOccurrence utility function', () => { + // Test 1: Test for next occurrence of a weekday + test('Should return the correct next Monday from today', () => { + const today = new Date(); + const result = getNextOccurrence('Monday'); + expect(new Date(result).getTime()).toBeGreaterThan(today.getTime()); // Ensure it's a future date + }); + + // Test 2: Test with a specific start date + test('Should return the next occurrence of Sunday from a given date', () => { + const result = getNextOccurrence('Sunday', new Date('2025-02-10')); // Monday + expect(result).toBe('Sun, 16 Feb 2025 00:00:00 GMT'); + }); + + // Test 3: Test if the function correctly rolls over to the next week + test('Should return the correct next Friday when today is Saturday', () => { + const result = getNextOccurrence('Monday', new Date('2025-02-28')); // Friday + expect(result).toBe('Mon, 03 Mar 2025 00:00:00 GMT'); + }); + + // Test 4: Test for invalid date + test('Should return "Invalid date" for an invalid date', () => { + const result = getNextOccurrence('Monday', 'ABC'); + expect(result).toBe('Invalid date'); + }); +}); diff --git a/src/get-next-occurrence/get-next-occurrence.ts b/src/get-next-occurrence/get-next-occurrence.ts new file mode 100644 index 0000000..8c5e64d --- /dev/null +++ b/src/get-next-occurrence/get-next-occurrence.ts @@ -0,0 +1,22 @@ +import { daysFull } from '../data/date.data'; + +type DayType = 'Sunday' | 'Monday' | 'Tuesday' | 'Wednesday' | 'Thursday' | 'Friday' | 'Saturday'; + +/** + * @function + * @description - Find the next occurrence of the given day. + * @param day - The day to find the next occurrence of; type: 'Sunday' | 'Monday' | 'Tuesday' | 'Wednesday' | 'Thursday' | 'Friday' | 'Saturday' + * @param startDate - The date to start checking from; type: Date | string | number; default: current date; optional + * @returns { string } Returns UTC value of the result date; type: string + */ +export const getNextOccurrence = (day: DayType, startDate: Date | string | number = new Date()): string => { + const date = new Date(startDate); + if (!(date instanceof Date) || isNaN(date.getTime())) return 'Invalid date'; + + const requiredDayIndex = daysFull.indexOf(day); + const currentDayIndex = date.getUTCDay(); + + const daysToAdd = requiredDayIndex - currentDayIndex + (requiredDayIndex < currentDayIndex ? 7 : 0); + date.setUTCDate(date.getUTCDate() + daysToAdd); + return date.toUTCString(); +}; diff --git a/src/index.ts b/src/index.ts index 773b110..b29bc15 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,3 +4,4 @@ export * from './index-to-name/index-to-name'; export * from './add-subtract-time/add-subtract-time'; export * from './is-valid-date/is-valid-date'; export * from './is-leap-year/is-leap-year'; +export * from './get-next-occurrence/get-next-occurrence'; diff --git a/src/is-valid-date/is-valid-date.ts b/src/is-valid-date/is-valid-date.ts index d5df414..455fe76 100644 --- a/src/is-valid-date/is-valid-date.ts +++ b/src/is-valid-date/is-valid-date.ts @@ -64,7 +64,7 @@ export const isValidDate = (date: unknown, format?: string): boolean => { console.error(error); } - if (!format || typeof date !== 'string') return isValid; + if (isValid || !format || typeof date !== 'string') return isValid; // Check if the format and date separators are the same. if (!checkIfAllSeparatorsAreValid(date, format)) return false;