diff --git a/test/validators.js b/test/validators.js index 959ba1dbd..cf6c6b007 100644 --- a/test/validators.js +++ b/test/validators.js @@ -855,16 +855,99 @@ describe('Validators', function () { validator: 'isDate' , valid: [ '2011-08-04' + , '2011-09-30' , '04. 08. 2011.' , '08/04/2011' + , '08/31/2011' , '2011.08.04' + , '2/29/24' + , '2-29-24' , '4. 8. 2011. GMT' + , '2. 28. 2011. GMT' + , '2. 29. 2008. GMT' , '2011-08-04 12:00' - ] + , '2/22/23' + , '2-23-22' + , '12' + , '11/2/23 12:24' + , new Date() + , 'Mon Aug 17 2015 00:24:56 GMT-0500 (CDT)' + , '2/22/23 23:24:26' + // valid ISO 8601 dates below + , '2009-12T12:34' + , '2009' + , '2009-05-19' + , '2009-05-19' + , '2009-05' + , '2009-001' + , '2009-05-19' + , '2009-05-19 00:00' + , '2009-05-19 14:31' + , '2009-05-19 14:39:22' + , '2009-05-19T14:39Z' + , '2009-05-19 14:39:22-06:00' + , '2009-05-19 14:39:22+0600' + , '2009-05-19 14:39:22-01' + , '2007-04-06T00:00' + , '2010-02-18T16:23:48.5' + , '200905' + , '2009-' + , '2009-05-19 14:' + , '200912-01' + // RFC 2882 tests below borrowed from the timerep package in Hackage: + // https://hackage.haskell.org/package/timerep-1.0.3/docs/src/Data-Time-RFC2822.html + , 'Fri, 21 Nov 1997 09:55:06 -0600' + , 'Tue, 15 Nov 1994 12:45:26 GMT' + , 'Tue, 1 Jul 2003 10:52:37 +0200' + , 'Thu, 13 Feb 1969 23:32:54 -0330' + , 'Mon, 24 Nov 1997 14:22:01 -0800' + , 'Thu, 13\n Feb\n 1969\n 23:32\n -0330' + , 'Thu, 13\n Feb\n 1969\n 23:32\n -0330 (Newfoundland Time)' + ,'24 Nov 1997 14:22:01 -0800' + // slight variations of the above with end-of-month + , 'Thu, 29\n Feb\n 1968\n 13:32\n -0330' + , 'Fri, 30 Nov 1997 09:55:06 -0600' + // more RFC 2882 tests borrowed from libgit2: + // https://github.com/libgit2/libgit2/blob/master/tests/date/rfc2822.c + , 'Wed, 10 Apr 2014 08:21:03 +0000' + , 'Wed, 9 Apr 2014 10:21:03 +0200' + , 'Wed, 9 Apr 2014 06:21:03 -0200' + , 'Wed, 9 Apr 2014 08:21:03 +0000' + ] , invalid: [ 'foo' , '2011-foo-04' + , '2011-09-31' + , '2. 29. 1987. GMT' + , '2. 29. 2011. GMT' + , '2/29/25' + , '2-29-25' , 'GMT' + //invalid ISO 8601 dates below + , '2009367' + , '2007-04-05T24:50' + , '2009-000' + , '2009-M511' + , '2009M511' + , '2009-05-19T14a39r' + , '2009-05-19T14:3924' + , '2009-0519' + , '2009-05-1914:39' + , '2009-05-19r14:39' + , '2009-05-19 14a39a22' + , '2009-05-19 14:39:22+06a00' + , '2009-05-19 146922.500' + , '2010-02-18T16.5:23.35:48' + , '2010-02-18T16:23.35:48' + , '2010-02-18T16:23.35:48.45' + , '2009-05-19 14.5.44' + , '2010-02-18T16:23.33.600' + , '2010-02-18T16,25:23:48,444' + , '2009-02-30 14:' + , '200912-32' + // hackage RFC2822 variants with invalid end-of-month + , 'Thu, 29\n Feb\n 1969\n 13:32\n -0330' + , 'Fri, 31 Nov 1997 09:55:06 -0600' ] }); }); diff --git a/validator.js b/validator.js index 7a038d6bc..47aa336c9 100644 --- a/validator.js +++ b/validator.js @@ -468,7 +468,34 @@ }; validator.isDate = function (str) { - return !isNaN(Date.parse(str)); + var normalizedDate = new Date((new Date(str)).toUTCString()); + var regularDay = String(normalizedDate.getDate()); + var utcDay = String(normalizedDate.getUTCDate()); + var dayOrYear, dayOrYearMatches, year; + if (isNaN(Date.parse(normalizedDate))) { + return false; + } + //check for valid double digits that could be late days + //check for all matches since a string like '12/23' is a valid date + //ignore everything with nearby colons + dayOrYearMatches = str.match(/(^|[^:\d])[23]\d([^:\d]|$)/g); + if (!dayOrYearMatches) { + return true; + } + dayOrYear = dayOrYearMatches.map(function(digitString) { + return digitString.match(/\d+/g)[0]; + }).join('/'); + year = String(normalizedDate.getFullYear()).slice(-2); + //local date and UTC date can differ, but both are valid, so check agains both + if (dayOrYear === regularDay || dayOrYear === utcDay || dayOrYear === year) { + return true; + } else if ((dayOrYear === (regularDay + '/' + year)) || (dayOrYear === (year + '/' + regularDay))) { + return true; + } else if ((dayOrYear === (utcDay + '/' + year)) || (dayOrYear === (year + '/' + utcDay))) { + return true; + } else { + return false; + } }; validator.isAfter = function (str, date) {