javascript regexp, validating date problem - javascript

I have some code for validating date below:
function validateForm() {
var errFound = 0;
//var patt_date = new RegExp("^((((19|20)(([02468][048])|([13579][26]))-02-29))|((20[0-9][0-9])|(19[0-9][0-9]))-((((0[1-9])|(1[0-2]))-((0[1-9])|(1\d)|(2[0-8])))|((((0[13578])|(1[02]))-31)|(((0[1,3-9])|(1[0-2]))-(29|30)))))$");
var patt_date = new RegExp("^[0-9]{4}-(((0[13578]|(10|12))-(0[1-9]|[1-2][0-9]|3[0-1]))|(02-(0[1-9]|[1-2][0-9]))|((0[469]|11)-(0[1-9]|[1-2][0-9]|30)))$");
if (patt_date.test(document.getElementById("datefrom").value) == false){errFound = errFound + 1;document.getElementById("datefrom").className = "error";}
if (errFound > 0)
alert('Please correct red colored field!');
else
return true;
return false;
}
Above code should work with YYYY-MM-DD format, but fail to validate date such as "2009-02-29"
The commented code should work (//var patt_date = new RegExp...), it can catch "2009-02-29", but it ruin the validation when i put invalid data and try to correct it, it keeps complain there something wrong with form value after i had correct them (especially on form with multiple input)
Maybe someone can fix the current regex?
Edited, what i want just a simple replacement for above regexp, mean a new regexp pattern not the whole new method to validate date
And for reference, i simply grab the regexp pattern from:
http://www.regexlib.com/REDetails.aspx?regexp_id=694 and
http://www.regexlib.com/REDetails.aspx?regexp_id=933
Tested with 2009-02-29, 1st link work & 2nd not. Again the problem was only the 2nd regexp didn't detect value 2009-02-29 as invalid while 1st can (but it ruin my code? so it's must be there something wrong with it).
Thanks,
Dels

Don't do the whole date validation with a regular expression, that's really pushing the limits of what regexps were designed for. I would suggest this procedure instead:
Check date against regexp /^\d{4}-\d{2}-\d{2}$/
Extract year, month, and day using substr() and convert to integers
Use some if statements to validate the integers. Like so:
if (month == 2) {
if (day == 29) {
if (year % 4 != 0 || year % 100 == 0 && year % 400 != 0) {
// fail
}
}
else if (day > 28) {
// fail
}
}
else if (month == 4 || month == 6 || month == 9 || month == 11) {
if (day > 30) {
// fail
}
}
else {
if (day > 31) {
// fail
}
(That could certainly be written more concisely) Alternatively, you could probably perform this validation using Javascript's Date class - you might have to do something like parsing the date, converting it back to a string, and checking if the two strings are equal. (I'm not a Javascript expert)

I kinda agree with David on this... Regex matches should not be used as an exclusive criterion to decide if the passed date is, in fact, valid. The usual procedure in Javascript validation involves a few steps :
a. The first step is to ensure that the passed string matches expected date formats by matching it against a Regex. The following may be a stricter Regex pattern.
// Assuming that the only allowed separator is a forward slash.
// Expected format: yyyy-mm-dd
/^[12][90][\d][\d]-[0-3]?[\d]-[01]?[\d]$/
b. The second step is to parse the string into a Date object which returns the no. of milliseconds since 1970. Use this number as a parameter for the Date constructor.
c. Since JS automatically rolls over the passed date to the nearest valid value, you still cannot be certain if the Date object created matches that which was passed. To determine if this happened, the best way is to split the passed string according to the separator and compare individual date components:
// d is the created Date object as explained above.
var arrDateParts = inputDate.split("-");
if ((d.getFullYear() == arrDateParts[0]) && (d.getMonth() == arrDateParts[1]) && (d.getDate() == arrDateParts[2]))
return true;
else
return false;

This javascript code validates date exactly. You can copy it and test it in your browser.
var regDate = '^(19[0-9]{2}|2[0-9]{3})-(0[1-9]{1}|1[0-2]{1}){1}-(0[1-9]|(1|2)[0-9]|3[0-1]){1}$';
var txt='2010-01-31';
if(txt.match(regDate))
{
alert('date match');
}

Related

Date input in javascript, detect if year, month or day was selected

Is it possible to detect event on different parts of an input date field.
<input type="date" value="2018-08-15">
In other words did the user select the year, the month or the day(in this specific scenario).
You could use .split.
Start at 0, then use a regex to separate user input at slashes.
Now you can check each array index for a value other than the default.
Something like this. (untested)
var d = document.getElementById('date').value;
var dArray = d.split(0, /\//);
for (var i = 0; i < i.length; i++;) {
if ((dArray[i] === 'mm') || (dArray[i] === 'dd') || (dArray[i] === 'yyyy') {
// date incomplete
}
}
Note: the date element doesn't have full browser support yet.
Unfortunately the date element refuses to give incomplete data (value returns nothing if the date is incomplete), but when it is complete we can simply check for changes from the last time it was changed, ignoring the empty arrays.
Do notice that the change event only fires on valid input changes (or from valid input to invalid input), so if a part of the date input (date/month/year) is invalid, the others won't trigger change until the invalid part is turned valid (which does trigger change).
function dateListener(e) {
let arr = e.target.value.split('-');
if(!this.prevArr)this.prevArr=[];
if(this.prevArr[0] != arr[0] && arr[0]) {
console.log(`The year was changed from ${this.prevArr[0]} to ${arr[0]}`);
}
if(this.prevArr[1] != arr[1] && arr[1]) {
console.log(`The month was changed from ${this.prevArr[1]} to ${arr[1]}`);
}
if(this.prevArr[2] != arr[2] && arr[2]) {
console.log(`The date was changed from ${this.prevArr[2]} to ${arr[2]}`);
}
if(arr[0]) this.prevArr=arr; //If the date is falsey (undefined/empty string), so is the whole array.
};
document.getElementById("datefield").addEventListener("change", dateListener);
<input type="date" id="datefield" />
What we're doing here is taking advantage of the fact that functions are objects, and settings a variable on the function to save the previous state of the input. Of course we don't have to do that and we could create a variable that's not bound to the function to save that date, but I chose to do this because of comfortability.

Checking if any given string is a valid date

Does anyone know of any way to check if strings are valid dates? I'm trying to block against invalid dates, while not forcing any kind of date format. Basically here's the problem:
!!Date.parse('hello 1') === true
Javascript can figure out a date from that string, therefore, it's a date. I'd rather it not be. Anyone?
How close would stripping out spaces around words get you? It at least weeds out "hello 1" and such.
Date.parse('hello 1'.replace(/\s*([a-z]+)\s*/i, "$1")); // NaN
Date.parse('jan 1'.replace(/\s*([a-z]+)\s*/i, "$1")); // Valid
[update]
Ok, so we'll just replace any non-alphanumerics that fall between a letter and a number:
replace(/([a-z])\W+(\d)/ig, "$1$2")
Since you're using moment.js, try using parsingFlags():
var m = moment("hello 1", ["YYYY/MM/DD"]).parsingFlags();
if (!m.score && !m.empty) {
// valid
}
It's the metrics used for isValid() and you can use them to make a stricter validation function.
Note: You can specify the other formats to support in the second argument's array.
Some other properties returned by parsingFlags() that might be of interest are the following:
m.unusedInput - Ex. ["hello "]
m.unusedTokens - Ex. ["MM", "DD"]
Use this function to check date
function isDate(s)
{
if (s.search(/^\d{1,2}[\/|\-|\.|_]\d{1,2}[\/|\-|\.|_]\d{4}/g) != 0)
return false;
s = s.replace(/[\-|\.|_]/g, "/");
var dt = new Date(Date.parse(s));
var arrDateParts = s.split("/");
return (
dt.getMonth() == arrDateParts[0]-1 &&
dt.getDate() == arrDateParts[1] &&
dt.getFullYear() == arrDateParts[2]
);
}
console.log(isDate("abc 1")); // Will give false
Working Fiddle
It would be ok if you check for several types of dates?
kind of this for narrow the permited dates:
if( givenDate.match(/\d\d\/\d\d\/\d\d\d\d/)
|| givenDate.match(/\w*? \d{1,2} \d{4}/)
|| givenDate.match(anotherFormatToMatch) )
UPDATED
Or, althougt it restrict characters, you coud use something like this:
function myFunction() {
var str = "The rain in SPAIN stays mainly in the plain";
var date = new Date(str);
if (date != "Invalid Date" && !isNaN(new Date(date) && !str.match(/a-z/g) )
alert(date);
}

Year of date validation is failing

I need to do a date validation to accept it in dd/mm/yyyy format. However all conditions are working fine except that if I enter year of 6 digits it is also accepting it, like -
12/12/200000
as per my code is valid. Below is my code:
function validate(value) {
if(!value.match(/\d\d\/\d\d\/\d\d\d\d/))
return false;
return checkdate(value);
}
function checkdate(val)
{
var dates = val.split(/\D/);
if(dates[0] <= 0 || dates[0] > 31)
return false;
if(dates[1] <= 0 || dates[1] > 12)
return false;
var now = new Date(dates[2],dates[1]-1,dates[0]);
if (isNaN(now))
return false;
now.setHours(0,0,0,0);
if (now.getFullYear() == dates[2] && now.getMonth() + 1 == dates[1] && now.getDate() == dates[0])
return true;
return false;
}
I am not sure why it allowing year as 6 digits valid input?
The problem is in validate function, regular expression it matches against allows input values you don't want to pass as valid. Besides obvious dd/mm/yyyy format, it allows found text to be anywhere in string. Basically, you said for it to check "if there's said expression inside string", when it should have been "if the whole string matches this expression".
To fix the issue, add ^ at the beginning and $ at the end. ^ stands for string start and $ for string end:
/^\d\d\/\d\d\/\d\d\d\d$/
I think you would benefit from reading documentation on regular expression syntax used by JavaScript.
While at at, humans tend to have issues reading long repeating sequences of similar characters, like in your regexp. This expression is easer to understand and does exactly the same thing:
/^\d{2}\/\d{2}\/\d{4}$/
You're not limiting the regex with start and stop delimiters, so 12/12/200000 is a match as it matched the regex, and then some
if (!value.match(/^\d\d\/\d\d\/\d\d\d\d$/) )
As a sidenote, you don't have to type \d four times, you can do \d{4} to match four instances of \d
If you want to validate a date string by creating a Date object, you don't need to check the entire pattern, just create and Date and check the result. Do you really need two digits for day and month number?
If you want a 4 digit year, that must be checked separately as the constructor will happily convert two digit years to 20th century. If you really need two digit day and month, that can be checked at the same time as the year:
function validateDMY(s) {
var b = s.split(/\D/);
var d = new Date(b[2], --b[1], b[0]);
return d && /^\d{4}$/.test(b[2]) && b[1] == d.getMonth();
}
console.log(validateDMY('30/02/2015')); // false
console.log(validateDMY('30/22/2015')); // false
console.log(validateDMY('02/02/15')); // false
console.log(validateDMY('30/01/2015')); // true

How can you stop a user from entering an incorrectly formatted date on the fly?

In a perfect world I would be able to stop the user from entering a character in a textbox on a asp.net page if it was not the next expected character in the specified date format.
For the format: dd-mm-yyyy if a user were to type "22" followed by anything but the "-" nothing would happen.
Is there a way this is possible using javascript, I have validation currently that checks the dates for the correct format, but this only occurs on a button click.
In this scenario all users will know the correct format, and should only ever be caught out when making a mistake, which this method should quickly (instantly) rectify.
If you are ready to use jquery then you can use
date mask plugin
http://plugins.jquery.com/project/DateMask
Add an onInput event handler, perform there the validation against the pattern, and rectify <input>'s value as desired.
If you are using jQuery, this: http://digitalbush.com/projects/masked-input-plugin/ is a descent masking plugin. If you are not using jQuery, you should start :)
Yeah, it can happen. Given a date format you can compare what the user entered via the KeyUp/KeyPress event of the text box in java script.
Using JQuery this can be implemented rather simply:
$(function(){
$('#mytextbox').bind('keypress', function(event){
//this assumes that the format is dd-mm-yyyy
//the text in the textbox
var text = $('#mytextbox').val();
//last character entered
var lastCharIndex = (text.length-1) < 0 ? 0 : (text.length -1);
var lastChar = text[lastCharIndex];
if( lastCharIndex == 0 ){ //corresponds to the first d in dd
} else if (lastCharIndex == 1 ) { //corresponds to the second d in dd
} else if (lastCharIndex == 2 ) { //corresponds to the first '-' in dd-mm-yyyy
} else if (lastCharIndex == 3 ) { //corresponds to the first m
} else if (lastCharIndex == 4 ) { //corresponds to the second m
} else if (lastCharIndex == 5 ) { //corresponds to the second '-'
} else if (lastCharIndex == 6 ) { //corresponds to the first y
} else if (lastCharIndex == 7 ) { //corresponds to the second y
} else if (lastCharIndex == 8 ) { //corresponds to the third y
} else if (lastCharIndex == 9 ) { //corresponds to the forth y
} else { //default error handling
}
});
});
So in each if statement all you have to check is if the e.keyCode (or the equivalent in the specified browser) is numeric or '-'. The reason I rather use the lastChar is so that I don't have to mess around figuring out what browser this is supposed to support...
Anyways if the lastChar is neither just set the textbox's text to be the text it already had minus the last character entered, unless of course the text entered only had 1 character in which case the text box's contents should be set to blank ''.
Bleepzter
A possibly cheap way I found is to use the OnKeyUp event (source), which will fire after every keystroke.

parseInt() returning incorrect value; DOB validation

Wondering if anyone could shed some light as I’m pulling my hair out over this one!
I have written a simple function to validate a users Date of birth which is all well and good, or at least it was until I realised it wasn't working as expected!
The function, as below, takes 2 parameters, dobNum (the value of an input field) and dmy (a switch variable that receives either ‘dd’, ‘mm’ or ‘yyyy’). The function is called as follows with the value of an input field so there shouldn’t be any object based problems:
onblur=”validateDOB(this.value, ‘mm’);
I have spent ages trying to get to the bottom of this and there seems to be a problem with the parseInt() statement.
This works fine for the days and months until you pass either a 08 (zero, eight) or a 09 (zero,nine). Here the result of the parseInt() returns as 0 rather than an 8 or 9 respectively.
But this is only a problem with 08 and 09, passing numbers 01 to 07 returns 1 to 7 as expected.
Similarly, when passing single digits, 1 to 9, to the function, parseInt() returns the appropriate value as an integer.
Really struggling to fathom this one out. Conversely removing the parseInt statement completely seems to work however this leaves the dobNum value as a string which I don’t feel is particularly good practice.
Can anyone shed some light on this please? (this problem occurs in both firefox and IE)
Many thanks,
SMc
var DOBddOK = false;
var DOBmmOK = false;
var DOByyyyOK = false;
function validateDOB (dobNum, dmy) {
// Set Regexp based on dmy var.
if (dmy.length == 2) var reg = /^([0-9]{1,2})$/;
else var reg = /^([0-9]{4})$/;
var numOK = reg.test(dobNum);
alert("NumOK: "+numOK); //test
// If dobNum value passes regExp test then convert it to an integer
if (numOK) {
var numVar = parseInt(dobNum);
//var numVar = dobNum;
alert("NumVar: "+numVar); //test
}
alert("dmy: "+dmy); //test
switch (dmy) {
case "dd":
if (numOK && numVar <= 31 && numVar > 0) DOBddOK = true;
else DOBddOK = false;
break;
case "mm":
if (numOK && numVar <= 12 && numVar > 0) DOBmmOK = true;
else DOBmmOK = false;
break;
case "yyyy":
var d = new Date();
d = d.getFullYear();
if (numOK && numVar <= (d-18) && numVar >= (d-80)) DOByyyyOK = true;
else DOByyyyOK = false;
break;
}
}
When the parseInt function finds a leading zero in the passed string, it will implicitly parse the number as octal.
It is always recommended to use the radix argument:
parseInt('08', 10); // 8
parseInt('09', 10); // 9
This have caused so many problems over the time that in the new version of the language standard, ECMAScript 5, the implicit octal detection has been removed from the parseInt algorithm. But ES5 is not completely supported yet.
There are other ways to convert a String to Number in JavaScript that do not present this problem, for example:
The unary plus operator:
+'08'; // 8
The Number constructor called as a Function:
Number('08'); // 8
In my opinion parseInt and the later two ways I've described have a (subtly) different semantic meaning.
The former is clearly parsing, for example:
parseInt('12px'); // 12
parseInt('10yo'); // 10
parseInt('1111', 2); // 15
And the last two ways are for doing String to Number type conversion.
It's treating strings with a leading zero as octal, you can specify a second parameter giving the radix as 10.
See link text
Try to use the radix parseInt(dobNum, 10) to parse your integer in base 10

Categories

Resources