john chesley

fresh stuff

destinations

favorites

validating dates

cross-browser date validation in javascript can be a little tricky. writing a single regular expression to check all dates may as well be impossible. searching around google, most date validation functions out there use a combination of a simple regex, and then use javascript's Date class to parse the date. the trouble is, some invalid dates still get parsed into real dates-- for example:

> new Date('13/32/2009')
Mon Feb 01 2010 00:00:00 GMT-0800 (PST)
>

what? so extra days and months just get carried over to the next year or month. hmm...but it's quirky- not all numbers wrap around:

> new Date('12/69/2009')
Sun Feb 07 2010 00:00:00 GMT-0800 (PST)
> new Date('12/70/2009')
Invalid Date
> new Date('69/13/2009')
Sat Sep 13 2014 00:00:00 GMT-0700 (PDT)
> new Date('70/13/2009')
Invalid Date
>

this output is from rhino, the javascript engine in firefox. it seems to allow up to 69 days in a month, or 69 months in a year, and carries over the remainder. v8, the javascript engine in google chrome, doesn't do this- unless a month has less than 31 days. months don't carry:

[v8]
> new Date('13/31/2009')
Invalid Date
> new Date('2/30/2009')
Mon Mar 02 2009 00:00:00 GMT-0800 (PST)

so, even using regex combined with new Date(...) won't get you consistent results across all browsers unless you check the date value you get back against the date string you passed in. luckily our regex can help us out a bit:

> var date_regex = /^([01]?[0-9]{1})(\/|-)([0-3]?[0-9]{1})(\/|-)([0-9]{4})$/
> date_regex.test('2/24/2009')
true
> date_regex.test('24/24/2009')
false
> '2/24/2009'.match(date_regex)
["2/24/2009", "2", "/", "24", "/", "2009"]
>

this regex is a little smarter than firefox, only allowing up to 19 months, or 39 days. it also uses grouping to make it easy to split it apart into bits. now we will be able to compare those bits to the date value that gets returned, and determine if it's the same date. here's tidbit from my form validation script-- slightly modified to stand on its own:

function checkdate(value) {
  var date_regex = /^([01]?[0-9]{1})(\/|-)([0-3]?[0-9]{1})(\/|-)([0-9]{4})$/
  if (!value.test(date_regex))
    return false;

  var m = value.match(date_regex);
  var d = new Date(value);
  return (d.getFullYear() == m[5]
      && d.getMonth()+1 == m[1]
      && d.getDate() == m[3]);
}

now only dates that really exist are validated. it even correctly handles leap years:

> checkdate('2/29/2009') // -> 2009 not a leap year
false
> checkdate('2/29/2008') // -> 2008 = leap year
true

beauty.

recent:

validating forms

using an ssh tunnel to connect to postgres

envjs, eh?