Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add new isDate() validator #1270

Merged

Conversation

mum-never-proud
Copy link
Contributor

@mum-never-proud mum-never-proud commented Mar 22, 2020

Resolves #1130

Copy link
Member

@profnandaa profnandaa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contribution and welcome to the project! 🎉 See my comments below.

@@ -1,8 +1,12 @@
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this file from the diff since it's unrelated to the PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was auto-generated

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just remove it before committing. This is because of the difference in the build system.

'2015-07-15T07:00:00+0000',
],
invalid: [
'',
Copy link
Member

@profnandaa profnandaa Mar 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try add the following test cases:

2020-02-30, // invalid date
2019-02-29, // non-leap year
2020-04-31, // invalid date

I presume all those will pass as true (or fail as false). We will need to handle these cases.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since:

> new Date('2020-02-31')
2020-03-02T00:00:00.000Z
> new Date('2020-04-31')
2020-05-01T00:00:00.000Z

Copy link
Contributor Author

@mum-never-proud mum-never-proud Mar 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice catch!

a simple validation would be

> new Date('2020-02-30').getUTCDate()
1
> new Date('2019-02-29').getUTCDate()
1
> new Date('2020-02-29').getUTCDate()
29

we can compare it with the date supplied

the problem here is with the date format some may give as YYYY-MM-DD or MM-DD-YYYY

we can do that! my bad

any suggestion?

any better way ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd not thought of that way, I think I like it! 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm looks like there are many edge cases to be considered in this case,

what if a user supplies

MM-DD-YYYY
YYYY-MM-DD
YY-MM-DD
MM-DD-YY

we need to keep things simple and general

any suggestion?

Copy link
Member

@profnandaa profnandaa Mar 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, for now let's just support those that are supported by Date(), and strictly YYYY. Need to add that note on the README.

However, I noticed something else, look at this?

> new Date('02-02-2019')
2019-02-01T21:00:00.000Z // .getUTCDate() = 1
> new Date('2019-02-02')
2019-02-02T00:00:00.000Z // .getUTCDate() = 2

Perhaps this are some of the intricacies that led to deprecating the first isDate() from the library. 🤔

What if we allowed the user to supply the format from a list of predefined formats?

MM-DD-YYYY
DD-MM-YYYY
YYYY-MM-DD

Then transform this to a YYYY-MM-DD format before running it through new Date()

Copy link
Contributor Author

@mum-never-proud mum-never-proud Mar 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check out the fiddle

https://jsfiddle.net/hvrwp07e/1/

I have done some tweaking, I have some stuff to do so right now I don't have time to think about edge cases

feel free to introduce some edge case or enhance the code

let me know if you are aware of any edge cases

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking forward to that we can do more addition on edge cases in the future and update the readme accordingly.

@profnandaa profnandaa changed the title add support for is date feat: add new isDate() validator Mar 22, 2020
@profnandaa
Copy link
Member

/cc. @tux-tn @ezkemboi -- your thoughts?

@ezkemboi
Copy link
Member

I will check on this @profnandaa.

@mum-never-proud
Copy link
Contributor Author

I have made the necessary changes to support almost all the format and handling leap years, invalid dates, etc

I have added a few more test cases, let me know if we need more test cases

have a look and let me know for any further changes!

cc: @profnandaa

Copy link
Member

@profnandaa profnandaa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggesting a rework to simplify, let me know if it makes sense.

Thanks for the efforts so far.

return new Date(`${dateObj.m}/${dateObj.d}/${dateObj.y}`).getDate() === +dateObj.d;
}

return Object.prototype.toString.call(input) === '[object Date]' && isFinite(input);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What this last call for? The assumption is that input will always be a string. You need to call assertString() at the top of the function...

@@ -0,0 +1,35 @@
function isValidFormat(format) {
return /(^(y{4}|y{2})[\/-](m{1,2})[\/-](d{1,2})$)|(^(m{1,2})[\/-](d{1,2})[\/-]((y{4}|y{2})$))|(^(d{1,2})[\/-](m{1,2})[\/-]((y{4}|y{2})$))/gi.test(format);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd thought we'll come up with multiple regex depending with the format provided, starting with YYYY/MM/DD as a default.

We said we'll keep it simple as just date string only, nothing else.

@mum-never-proud
Copy link
Contributor Author

mum-never-proud commented Mar 26, 2020

Suggesting a rework to simplify, let me know if it makes sense.

Thanks for the efforts so far.

agreed that the regex part might seem complicated but its quite simple, I guess it's better to support all format with a little effort

let me break down this code into simple chunks

isDate supported argument types

object: check if the object type is Date
string: if string proceed with below steps

function isValidFormat(format) {
  return /(^(y{4}|y{2})[\/-](m{1,2})[\/-](d{1,2})$)|(^(m{1,2})[\/-](d{1,2})[\/-]((y{4}|y{2})$))|(^(d{1,2})[\/-](m{1,2})[\/-]((y{4}|y{2})$))/gi.test(format);
}

this part checks for the following patterns

  • YYYY-MM-DD

  • YY-MM-DD

  • YYYY-M-D

  • YY-M-D

  • MM-DD-YYYY

  • MM-DD-YY

  • M-D-YYYY

  • M-D-YY

  • DD-MM-YYYY

  • DD-MM-YY

  • D-M-YYYY

  • D-M-YY

function zip(x, y) {
  const zippedArr = [],
    len = Math.min(x.length, y.length);
  let i = 0;

  for (; i < len; i++) {
    zippedArr.push([x[i], y[i]]);
  }

  return zippedArr;
}

the above one just zips two arrays into one, for example, consider the input as 07/15/2002 and format as MM/DD/YYYY

splitting the above inputs [\/-] will yield two arrays

zipping them will yield this

['MM', '07']
['DD', '15']
['YYYY', '2002']

after zipping the arrays in this part

for (const [dateWord, formatWord] of dateAndFormat) {
      if (dateWord.length !== formatWord.length) {
        return false;
      }

      dateObj[formatWord.charAt(0)] = dateWord;
    }

we just check for length equality for eg. 'MM'.length === '07'.length if not we return false else we store in an object with first character of format

obj[d] = 15, obj[m] = 7, obj[y] = 2002

then we init the date and check for validity by getting the date and the original input if both dates are same it is a valid date else nope

let me know if anything is unclear, I hope this should work for almost all of the cases you can also refer the test cases

cc: @profnandaa

@profnandaa
Copy link
Member

@mum-never-proud -- ok, sounds good. Thanks!

Copy link
Member

@profnandaa profnandaa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

More review from @tux-tn and @ezkemboi then we land. Thanks for your contrib! 🎉

@profnandaa
Copy link
Member

@ezkemboi -- ping

@ezkemboi
Copy link
Member

ezkemboi commented Apr 1, 2020

Doing the review @profnandaa. I was held up by some work here.

validator: 'isDate',
valid: [
new Date(),
new Date([2014, 2, 15]),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This means we allow users to send created dates using the new Date() method?
I thought, we just need to pass a string. But, it is a good idea.

return /(^(y{4}|y{2})[\/-](m{1,2})[\/-](d{1,2})$)|(^(m{1,2})[\/-](d{1,2})[\/-]((y{4}|y{2})$))|(^(d{1,2})[\/-](m{1,2})[\/-]((y{4}|y{2})$))/gi.test(format);
}

function zip(x, y) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I would prefer if we make use of something like

function zip(date, format) {}

Use of x, y a little bit makes the code harder to read.

len = Math.min(x.length, y.length);
let i = 0;

for (; i < len; i++) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for(let i = 0; i < len; i++) {} 

Might seem better than let i = 0 and use ; to make separation.

@profnandaa
Copy link
Member

@mum-never-proud -- ^

@mum-never-proud
Copy link
Contributor Author

@profnandaa sorry was busy, I will update the changes in few hours!

@profnandaa profnandaa merged commit ff11844 into validatorjs:master Apr 6, 2020
@pavan-shipmnts
Copy link

When is this releasing?

@profnandaa
Copy link
Member

Most likey by end of May or 1st half of June.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

isDate()
4 participants