1

I'm trying to find a best way to test if a string fits a current criteria. Basically, I have a date coming in as such:

1/17/2013  12:00 AM

The month and day fields can be one or two digits, while the year is always four. The hour can be one or two digits. The minute field is always two digits For example, this is also applicable:

 10/1/2013  1:00 AM

Right now, I have this regex, but it doesn't seem to be working:

/^(0[1-9]|1[0-2])\/(0[1-9]|[1-2][0-9]|3[0-1])\/(20[1-9][2-9]) (0[1-9]|1[0-2]):([0-5][0-9]) (am|pm)$/

I am using it as such:

 $('input[name=targetMe]').each( function() {
        alert('start')
        if(/^(0[1-9]|1[0-2])\/(0[1-9]|[1-2][0-9]|3[0-1])\/(20[1-9][2-9]) (0[1-9]|1[0-2]):([0-5][0-9]) (AM|PM)$/.test($(this).val())) {
              alert('passes')
        } else {
              alert('dont')
        }
  });

Is there something wrong with my current regex, or should I be using it in another way, or is there a better solution out there than this?

Teneff
  • 30,564
  • 13
  • 72
  • 103
streetlight
  • 5,968
  • 13
  • 62
  • 101

4 Answers4

1

I believe you can use the parse method in Javascript:

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/parse

so it will be something like:

$('input[name=targetMe]').each( function() {
    alert('start')
    if(Date.parse($(this).val())) {
          alert('passes')
    } else {
          alert('dont')
    }
});
João Castro
  • 45
  • 1
  • 6
  • This is great! However, if the user passes a number in the input it still returns as 'passes'. Is there a way around this?? I very much like this method though! – streetlight Jan 03 '13 at 12:54
  • I also tried a similar solution in http://stackoverflow.com/questions/8082703/regex-for-testing-date-formatting?rq=1, but it also fails if the user passes a number. Would it be good to combine this with another method as well? – streetlight Jan 03 '13 at 13:00
  • In my opinion if you want to accept all tipes of dates you could use this method but if you only want to accept dates in a specific format you could use inline selects. You could also use `str.split("/")` `str.split(" ")` for example and above the input specify the format you expect. – João Castro Jan 03 '13 at 13:09
1

Try:

/^(0?[1-9]|1[0-2])\/(0?[1-9]|[12]\d|3[01])\/(20[1-9]\d) (0?[1-9]|1[0-2]):([0-5]\d) ([AP]M)$/

Note that this matches any year from (and including) 2010 to 2099. Your regex implies you only want years from 2012-2099, in which case, use something like 20(1[2-9]|[2-9]\d)

Xophmeister
  • 8,884
  • 4
  • 44
  • 87
  • I can't seem to get this to pass any of my dates, like '1/17/2013 12:00 AM' for example. Am I writing it incorrectly in the function? Also, I would like to accept any year if possible, as long as it's four digits, that my have been an oversight on my side – streetlight Jan 03 '13 at 12:57
  • In your copy-and-pasted examples, there's extra whitespace that wouldn't be accounted for in my regex. If you remove this (i.e., use single spacing), it works fine for me. If you can't remove the extra whitespace, you need to change the regex appropriately... If you want any year from 2000-2999, then use `2\d{3}` – Xophmeister Jan 03 '13 at 13:01
  • 1
    @NaveedS In JavaScript, regular expression literals are defined using the syntax `/regex/flags`. That is, the `/` is used as a delimiter, so if you want to include `/` in your expression, it needs to be escaped. – Xophmeister Jan 03 '13 at 13:04
  • @Xophmeister Sorry, I didn't know how to use regex in Javascript. Thanks for the info. – Naveed S Jan 03 '13 at 13:06
  • I have combined this with this post -- http://stackoverflow.com/questions/3286874/remove-all-multiple-spaces-in-javascript-and-replace-with-single-space -- to remove the blank spaces temporarily and pass them to the function! The only last thing I'm trying to implement is to have any year be valid. – streetlight Jan 03 '13 at 14:00
  • It would be easier to tweak my regex than striping extra spaces out: Something like this `/(0?[1-9]|1[0-2])\/(0?[1-9]|[12]\d|3[01])\/(2\d{3})\s+(0?[1-9]|1[0-2]):([0-5]\d)\s+([AP]M)/` will allow for extra spacing and any year from 2000-2999. Bear in mind that I've removed the `^` and `$` anchors: If you can guarantee your input, you won't need to worry about these. – Xophmeister Jan 03 '13 at 14:12
1

You can try Date.Parse to try to determine if the string is a valid date. However, as the method is implemenation dependant, you should also read the notes on this - javascripts and dates what mess.

To answer the orignal question, a simple regex as below should suffice.

^([1-9]|1[0-2]?)/([1-9]|[1-2][0-9]|3[0-1])/(19|20)[0-9][0-9] +(0?[0-9]|1[0-2]?):[0-5][0-9] +(a|p)m$

** Corrected to filter some incorrect values - Digits != Time **

The above will validate a date if the days and months are 1 or 2 digits, year is four with the starting digits begining 20, hours are 1 or 2 digits and minutes are 2 digits. The date and time are separated by two spaces.

I have used the RegExp object as the direct input seems to have an issue with / being interrupted as end of expression. Also, I have added "i" flag for case insensitive search for am/pm. Either escape it or change to use the object.

var regex = "^([1-9]|1[0-2]?)/([1-9]|[1-2][0-9]|3[0-1])/(19|20)[0-9][0-9] +(0?[0-9]|1[0-2]?):[0-5][0-9] +(a|p)m$";

var val = "1/17/2013  12:00 AM";
if(new RegExp(regex, "i").test(val)){
    alert("Success");
} else {
    alert("Fail");
}
Kami
  • 19,134
  • 4
  • 51
  • 63
  • This seems to pass in the regex testers, but when I try to put it in my function I get a JS error saying ' SyntaxError: Unexpected token '^''. How do I tie this into my existing function (thank you so much for your help, I'm not a regex ninja yet!) – streetlight Jan 03 '13 at 13:09
  • I'm trying this... if(^\d{1,2}/\d{1,2}/20\d{2}\s{2}\d{1,2}\:\d{2} (P|A)M$.test($(this).val())) { alert('passes') } else { alert('dont') } – streetlight Jan 03 '13 at 13:10
  • There is an issue with using digits, thanks to my colleague for pointing out. The inital regex would have accepted 88:88 PM quite happly. Use `/` at the end and start. – Kami Jan 03 '13 at 13:14
  • This seems pretty amazing! However, I am continuing to get JS errors when I try to integrate it with a function. I am now getting a 'customMetaData_editor.js:485SyntaxError: Expected token ':'' error. Would it be possible for you to illustrate how to integrate this particular regex within a function? – streetlight Jan 03 '13 at 13:20
  • Or maybe just point me in the write direction if possible? Thank you again for all of your help so far – streetlight Jan 03 '13 at 13:37
  • @streetlight I have added a jsfiddle with a working example of the regex. Hope it helps. – Kami Jan 03 '13 at 15:37
1

Okay, this is the final solution I found that combines all the great input I received here!

$('input[name=targetMe]').each( function() {
    alert('start')
    if(/^([1-9]|1[0-2])\/([1-9]|[1-2][0-9]|3[0-1])\/(19[0-9][0-9]|20[0-9][2-9]) (0[1-9]|1[0-2]):([0-5][0-9]) (am|pm|AM|PM)$/.test($(this).val())) {
          alert('passes')
    } else {
          alert('dont')
    }

});

This will accept anything in the 1900s or 2000s, and single and double digits for days and months.

streetlight
  • 5,968
  • 13
  • 62
  • 101