Skip to content

Commit

Permalink
Merge pull request #10 from anveshkolluri93/leapYearValidation
Browse files Browse the repository at this point in the history
Adds leap-year validation and handles invalid separator/s
  • Loading branch information
anveshkolluri93 authored Jul 21, 2023
2 parents e315052 + fbfe10a commit 477f9df
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 91 deletions.
2 changes: 1 addition & 1 deletion node_modules/.package-lock.json

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

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": "validate-date",
"version": "2.0.3",
"version": "2.1.0",
"description": "date validation",
"main": "validate-date.js",
"scripts": {
Expand Down
19 changes: 13 additions & 6 deletions validate-date-test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ describe('validateDate function', () => {
expect(validateDate('2023-07-32')).toBe('Invalid Date');
expect(validateDate('2023-13-01')).toBe('Invalid Date');
expect(validateDate('02/29/2001')).toBe('Invalid Date');
// TODO- Fix the regex to handle this case.
// expect(validateDate('2023/02/29')).toBe('Invalid Date');
expect(validateDate('1752-09-02')).toBe('Invalid Date');

// Non leap year, 29 february
expect(validateDate('2023-02-29', 'string', 'yyyy-mm-dd')).toBe('Invalid Date');
expect(validateDate('2099-02-29', 'string', 'yyyy-mm-dd')).toBe('Invalid Date');
});

// Test invalid date values that should throw exceptions
Expand All @@ -32,6 +34,8 @@ describe('validateDate function', () => {

// Testing with an object as dateValue
expect(() => validateDate({ key: 'value' }, 'string')).toThrow('dateValue must be a string.');

expect(() => validateDate('2099-02-29', 'string', 'yyyy/mm/dd').toThrow('Use a valid separator. - or /.'));
});

it('should handle invalid dates with boolean response type', () => {
Expand All @@ -44,6 +48,7 @@ describe('validateDate function', () => {
// Test invalid response types
it('should throw an error for an invalid response type', () => {
expect(() => validateDate('2023-07-20', 'number')).toThrow("responseType must be 'string' or 'boolean'.");
expect(() => validateDate(null, 'number')).toThrow("dateValue must be a string.");
});

// testing with different date formats
Expand All @@ -57,9 +62,11 @@ describe('validateDate function', () => {
// testing with invalid date formats
it('should handle invalid date formats', () => {
expect(validateDate('2023-07-20', 'string', 'dd-MM-yyyy')).toBe('Invalid Format');
// TODO- Fix the regex to handle this case.
// expect(validateDate('07/20/2023', 'string', 'yy/mm/dd')).toBe('Invalid Format');
// expect(validateDate('2023/20/07', 'string', 'yyyy-mm-dd')).toBe('Invalid Format');
// expect(validateDate('20-07-2023', 'string', 'dd/mm/yy')).toBe('Invalid Format');
expect(validateDate('2023-20-07', 'string', 'yyyy/dd/mm')).toBe('Invalid Format');
expect(validateDate('2023/20/07', 'string', 'yyyy-mm-dd')).toBe('Invalid Format');
expect(validateDate('20-07-2023', 'string', 'dd/mm/yy')).toBe('Invalid Format');

// Format mismatch leading to invalid date.
expect(validateDate('07/20/2023', 'string', 'yy/mm/dd')).toBe('Invalid Date');
});
});
166 changes: 85 additions & 81 deletions validate-date.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
function validateDate(dateValue, responseType = "string", dateFormat = null) {
// Validate input parameters
if (typeof dateValue !== "string") {
throw new Error("dateValue must be a string.");
}

if (typeof responseType !== "string" || !["string", "boolean"].includes(responseType)) {
throw new Error("responseType must be 'string' or 'boolean'.");
}

if (dateFormat !== null && typeof dateFormat !== "string") {
throw new Error("dateFormat must be a string.");
}

if (dateValue.trim() === "") {
return responseType === "string" ? "Invalid Format" : false;
}
// Validate input parameters
if (typeof dateValue !== "string") {
throw new Error("dateValue must be a string.");
}

if (typeof responseType !== "string" || !["string", "boolean"].includes(responseType)) {
throw new Error("responseType must be 'string' or 'boolean'.");
}

let responses = responseSetter(responseType)
if (dateValue == null) {
return responses[0];
if (dateFormat !== null && typeof dateFormat !== "string") {
throw new Error("dateFormat must be a string.");
}

// Throw an exception for empty dateValue
if (dateValue.trim() === "") {
throw new Error("dateValue cannot be empty.");
}

let responses = responseSetter(responseType);

return dateValidator(dateValue, responses, dateFormat);
}

Expand All @@ -46,76 +44,82 @@ function daysInMonth(year, month) {
function getAllIndexes(arr, val) {
var indexes = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] === val) indexes.push(i);
if (arr[i] === val) indexes.push(i);
}

return indexes;
}

function isLeapYear(year) {
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) && year >= 1753;
}

function dateValidator(dateValue, responses, dateFormat) {
if (dateValue) {

if (!dateFormat) {
dateFormat = dateValue.includes("-") ? "yyyy-mm-dd" : "mm/dd/yyyy";
}

if (dateFormat.length > 10 || dateFormat.length < 6) return responses[0];

const formatSplit = dateValue.includes("-")
? dateFormat.split("-")
: dateFormat.split("/");

let wrongFormat = formatSplit
.map((formatPart) => /([dmy])\1/i.test(formatPart))
.filter((rightFormat) => !rightFormat);

if (wrongFormat.length > 0) return responses[0];

let dateSeparator = dateValue.includes("-") ? "-" : "/";

let formatRegex = new RegExp(
`(\\d{${formatSplit[0].length}})(${dateSeparator})(\\d{${formatSplit[1].length}})(${dateSeparator})(\\d{${formatSplit[2].length}})`
);

let dayPosition = getAllIndexes(
formatSplit,
formatSplit.filter((formatPart) => /[d]/i.test(formatPart))[0]
);
let monthPosition = getAllIndexes(
formatSplit,
formatSplit.filter((formatPart) => /[m]/i.test(formatPart))[0]
);
let yearPosition = getAllIndexes(
formatSplit,
formatSplit.filter((formatPart) => /[y]/i.test(formatPart))[0]
);

if (dayPosition.length !== 1 ||
monthPosition.length !== 1 ||
yearPosition.length !== 1
) {
return responses[0];
}

if (formatRegex.test(dateValue)) {
const dateSplit = dateValue.split(dateSeparator);
const day = Number(dateSplit[dayPosition]);
const month = Number(dateSplit[monthPosition]);
const year = Number(dateSplit[yearPosition]);
if (
month <= 0 ||
month > 12 ||
day > daysInMonth(year, month) ||
day <= 0 ||
year < 1753)
{
return responses[1];
}
} else {
return responses[0];
}
if (dateValue) {
if (!dateFormat) {
dateFormat = dateValue.includes("-") ? "yyyy-mm-dd" : "mm/dd/yyyy";
}

const dateSeparator = /[^dmy]/i.exec(dateFormat)[0]; // Extract the separator character

if (!dateValue.includes(dateSeparator)) {
return responses[0];
}

if (dateFormat.length > 10 || dateFormat.length < 6) return responses[0];

const formatSplit = dateValue.includes("-") ? dateFormat.split("-") : dateFormat.split("/");
let wrongFormat = formatSplit
.map((formatPart) => /([dmy])\1/i.test(formatPart))
.filter((rightFormat) => !rightFormat);

if (wrongFormat.length > 0) return responses[0];

// let dateSeparator = dateValue.includes("-") ? "-" : "/";

let formatRegex = new RegExp(
`(\\d{${formatSplit[0].length}})(${dateSeparator})(\\d{${formatSplit[1].length}})(${dateSeparator})(\\d{${formatSplit[2].length}})`
);

let dayPosition = getAllIndexes(
formatSplit,
formatSplit.filter((formatPart) => /[d]/i.test(formatPart))[0]
);
let monthPosition = getAllIndexes(
formatSplit,
formatSplit.filter((formatPart) => /[m]/i.test(formatPart))[0]
);
let yearPosition = getAllIndexes(
formatSplit,
formatSplit.filter((formatPart) => /[y]/i.test(formatPart))[0]
);

if (dayPosition.length !== 1 || monthPosition.length !== 1 || yearPosition.length !== 1) {
return responses[0];
}

if (formatRegex.test(dateValue)) {
const dateSplit = dateValue.split(dateSeparator);
const day = Number(dateSplit[dayPosition]);
const month = Number(dateSplit[monthPosition]);
const year = Number(dateSplit[yearPosition]);

// Check for invalid dates
if (
month <= 0 ||
month > 12 ||
day <= 0 ||
day > daysInMonth(year, month) ||
year < 1753 ||
(month === 2 && day === 29 && !isLeapYear(year))
) {
return responses[1];
}
} else {
return responses[0];
}
}

return responses[2];
}

Expand Down

0 comments on commit 477f9df

Please sign in to comment.