2 or 4 Digit Date Validation with Javascript String Replacement - javascript

EDIT: To anyone making the same mistake I did in asking this question, please look for my amended answer below which demonstrates a MUCH cleaner solution to this problem.
Trying to permit user entry of either 2 digit or 4 digit date format and allow both to pass validation but autocorrect the 2 digit format with the 4 digit equivalent with the assumption that the leading 2 digits should be the same as the current leading 2 digits.
I'm having trouble with the javascript replace() function. This line:
input.replace(enteredDate, year);
is not working as expected. In the context of the spine.js framework I'm using, the input refers to $(event.target) and appears to be correct everywhere else in manipulating the input field where the validation should be occurring. Ultimately, I want to replace the original string found in the input field with the fully concatenated one (which I haven't built out yet), but for now, how can I replace the contents of input (where input is var = $(event.target)) with the var year assigned here:
var year = currentYear.charAt(0) + currentYear.charAt(1) + unparsedYear;
Here is the full code for the function I have so far, which is throwing the following error in reference to the .replace() line - Uncaught TypeError: Object [object Object] has no method 'replace'
validateDate: function(event) {
var input = $(event.target);
var enteredDate = input.val();
input.destroyValidationMessage();
var pattern = /^(\d{1,2})\/(\d{1,2})\/(\d{2})|(\d{4})$/;
var result = enteredDate.match(pattern);
if (result !== null) {
var month = parseInt(result[1], 10);
var day = parseInt(result[2], 10);
var year = parseInt(result[3], 10);
var unparsedYear = parseInt(result[3], 10);
var unparsedYearStrLength = unparsedYear.toString().length;
if ( unparsedYearStrLength < 4) {
var currentYear = new Date().getFullYear().toString();
var year = currentYear.charAt(0) + currentYear.charAt(1) + unparsedYear;
alert('Autocorrected year will be ' + year);
input.replace(enteredDate, year);
}
var date = new Date(year, month - 1, day);
var isValid = date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day;
} else {
input.createValidationMessage('Invalid Date');
input.addClass('invalid');
}
}

As mentioned in my comment above:
input is a DOM element, but you actually want to replace the content of the element vs. the element itself, so use input.val(new_value) and not the actual input element.

Related

i want to fetch specific years into a variable and later display it inside paragraph ,it is a javascript code to display 1st january is being sunday

sunday();
function sunday()
{
let result;
let text1;
let year;
for (year = 2014; year <= 2050; year++)
{
var d = new Date(year, 0, 1);
if (d.getDay() === 0 )
console.log("1st January is being a Sunday "+year);
text1+=year.toString();//not get stored in variable text1
result=text1.toString();//same problem here also
}
}
please tell me why i cant store those years into text1(variable) even after i convert into string format also when i check console everything is works perectly in console result but it wont work when i store and try to display through paragraph using .innerhtml property help me to display it inside paragraph inner text
You have a syntax error near your if statement, you forgot to insert brackets.
Also, you can't append a text to a variable only defined with let.
If it's a string, you should do let text1 = ""
Furthermore, it is not very useful to append multiple results to the same string, which only gives something like this : "20172030" etc... by appending years. I think what you are trying to do is use arrays, which can be initialized by doing : let text1 = []
The code works and should look like this :
function sunday(){
let result;
let text1 = [];
let year;
for (year = 2014; year <= 2050; year++){
var d = new Date(year, 0, 1);
if (d.getDay() == 0 ){
console.log("1st January is being a Sunday "+year);
text1.push(year.toString());
console.log(text1);
result = text1.join(",");
console.log(result)
}
}
}
sunday()
There seem to be several problems here
Firstly you are not initializing the variable text1 with a string value. So the value of this will become a string undefined in a string concatenating context (your += in text1+=year.toString())
See these examples for a demonstration
let x
x+="2021"
console.log(x) // Output undefined2021
let x = "" // x is initialized with an empty string
x+="2021"
console.log(x) // Output 2021
Then we do not know, in which context you are calling the function. At least you do not return any value from it. If you add return text1 at the end of the function, your code might work.

internet explorer match() not working correctly

I have a really weird error on IE.
I am using knockout custom validations. And one of my custom validations is to validate date.
function:
function isValidDate(txtDate) {
var currVal = txtDate;
if (currVal == '' || currVal == null)
return false;
//Declare Regex
var rxDatePattern = /^(\d{1,2})(\/|-)(\d{1,2})(\/|-)(\d{4})$/;
var dtArray = currVal.match(rxDatePattern); // is format OK?
if (dtArray == null)
return false;
/*continue of logic*/
}
This works great, when I run it first time. But then I do a redirect to server and return to the same page.
And the validation is called again at that point the problem begins.
I have a two snapshots of memory. They look identical to me. But there has to be some difference that I don't see or the match method is somehow broken.
The difference is not the dtArray == null that is the problem. You can try to run it in console. And it parse the dtArray correctly....
Both snapshot are on the same line ( if (dtArray == null) )
beforeRedirect:
afterRedirect:
Update. I solved my problem.
problem was that I was setting my observable property something like this:
var date = "1990-01-01T00:00:00";
var dob = new Date(date).toLocaleDateString();
masterModel.Dob(dob);
when I do it like this the match works fine now:
var date = "1990-01-01T00:00:00"
var dob = new Date(date);
var dobstring = dob.getDate() + "/" + (dob.getMonth()+1) + "/" + dob.getFullYear();
masterModel.Dob(dobstring);
if you want to see the difference run this on IE in console. My IE version is 11.0.9600
//because I am in UK my locale string is dd/MM/yyyy if you get different one this problem won't work for you!
var date = "1990-01-01T00:00:00"
var dob = new Date(date).toLocaleDateString();
var rxDatePattern = /^(\d{1,2})(\/|-)(\d{1,2})(\/|-)(\d{4})$/;
console.log(dob);
console.log(dob.match(rxDatePattern));
//vs
var date = "1990-01-01T00:00:00"
var dob = new Date(date);
var dobstring = dob.getDate() + "/" + (dob.getMonth()+1) + "/" + dob.getFullYear();
var rxDatePattern = /^(\d{1,2})(\/|-)(\d{1,2})(\/|-)(\d{4})$/;
console.log(dobstring);
console.log(dobstring.match(rxDatePattern));
Try simply checking for falsy values. The empty string, null and undefined are all falsy, there is no need to be more specific than that here.
function isValidDate(txtDate) {
if (!txtDate) return false;
var rxDatePattern = /^(\d{1,2})(\/|-)(\d{1,2})(\/|-)(\d{4})$/;
var dtArray = currVal.match(rxDatePattern);
if (!dtArray) return false;
/*continue of logic*/
}
That being said, I strongly suggest you use a date library (most prominently: moment.js) to do any date parsing, -calculation and -validation work. Don't roll your own regex when a fully functional and properly tested library has been written.
To think one step further, with knockout it's much easier to store an actual date object in an observable, so there is no need to parse any date strings at all, ever. You can also format it for display on screen any way you like, instead of limiting yourself/the user to a single format.
This way you would not need to do any date format validation at all. Either the observable contains a date - or not. For best effect use that together with a date picker widget (for example the one from knockout-jqueryui).
View model:
this.exampleDate = ko.observable();
View, assuming jQueryUI + knockout-jqueryui:
<input type="text" data-bind="datepicker: {
dateFormat: 'dd.mm.yyyy'
}, value: exampleDate" />

Multiple RegExp in single function

This is not exactly a problem, but more a question of method.
I am working on a project where people are able to type shorthand dates in input field, for example if you simply type "20", the input will automatically display the full date for 20th of this month.
There are many shorthand types possible, so I had to make multiple RegExp and then check each and every one.
My question is, is there a better way to deal with this? I am no javaScript expert,but I have a feeling that this is not exacty "best practise".
Here is the function
function dateParser(date) {
var splitDate = date.split(/[.:\s]/);
var day = new RegExp(/\b\d{1,2}\b/);
var dateHour = new RegExp(/\b\d{1,2}\s\d{1,2}\b/);
var dateHourMin = new RegExp(/\b\d{1,2}\s\d{1,2}[:]\d{1,2}\b/);
var dateMonth = new RegExp(/\b\d{1,2}[\/\-\,\.]\d{1,2}\b/);
var dateMonthHour = new RegExp(/\b\d{1,2}[\/\-\,\.]\d{1,2}\s\d{1,2}\b/);
var dateMonthHourMin = new RegExp(/\b\d{1,2}[\/\-\,\.]\d{1,2}\s\d{1,2}[:]\d{1,2}\b/);
var dateMonthYear = new RegExp(/\b\d{1,2}[\/\-\,\.]\d{1,2}[\/\-\,\.]\d{1,4}\b/);
var dateMonthYearHour = new RegExp(/\b\d{1,2}[\/\-\,\.]\d{1,2}[\/\-\,\.]\d{1,4}\s\d{1,2}\b/);
var dateMonthYearHourMin = new RegExp(/\b\d{1,2}[\/\-\,\.]\d{1,2}[\/\-\,\.]\d{1,4}\s\d{1,2}[:]\d{1,2}\b/);
var month = new Date().getMonth() + 1;
var year = new Date().getFullYear();
var newDate;
if(dateMonthYearHourMin.test(date)) {
newDate = splitDate[0]+"."+splitDate[1]+"."+splitDate[2]+" "+splitDate[3]+":"+splitDate[4];
}
else if(dateMonthYearHour.test(date)) {
newDate = splitDate[0]+"."+splitDate[1]+"."+splitDate[2]+" "+splitDate[3]+":00";
}
else if(dateMonthYear.test(date)) {
newDate = splitDate[0]+"."+splitDate[1]+"."+splitDate[2]+" 12:00";
}
else if(dateMonthHourMin.test(date)) {
newDate = splitDate[0]+"."+splitDate[1]+"."+year+" "+splitDate[2]+":"+splitDate[3];
}
else if(dateMonthHour.test(date)) {
newDate = splitDate[0]+"."+splitDate[1]+"."+year+" "+splitDate[2]+":00";
}
else if(dateMonth.test(date)) {
newDate = splitDate[0]+"."+splitDate[1]+"."+year+" 12:00";
}
else if(dateHourMin.test(date)) {
newDate = splitDate[0]+"."+month+"."+year+" "+splitDate[1]+":"+splitDate[2];
}
else if(dateHour.test(date)) {
newDate = splitDate[0]+"."+month+"."+year+" "+splitDate[1]+":00";
}
else if(day.test(date)) {
newDate = splitDate[0]+"."+month+"."+year+" 12:00";
}
return newDate;
}
I believe you can consolidate some of your regular expressions and make this more compact.
The first thing I notice is that whitespace appears to be an important separator in your input strings. Specifically, the date (or day) is always separated from the hour/minute with a space. So the first thing I would do is split your input on a space:
var parts = date.split( /\s/ );
var datePart = parts[0];
var timePart = parts[1]; // could be undefined
Now we can process the date part and the time part (if it exists) separately. The components of your date part are always separated by a slash, a dash, a comma, or a period, so again we can just split it:
parts = datePart.split( /[\/\-\,\.]/ );
var day = parts[0];
var month = parts[1] // could be undefined
var year = parts[2]; // could be undefined
You can split the time similarly, since hours and minutes are always separated by a colon:
if( timePart ) {
parts = timePart.split( /:/ );
var hour = parts[0];
var minute = parts[1]; // could be undefined
}
This should make this a little more compact and easy to read and maintain. You could go even more compact with a singular regular expression with groups, but I feel that this approach would be better.
The problem you described is tackled by Natural Language Processing, Programming/Query Language Design fields.
One of the approaches for solving those kind of problems is manually written scanner using RegExp/other string scanning and working with the result the way you did. It works for simple languages, doesn't require much knowledge in language design department and usually is intuitive to modify.
If you however have feeling that input is going to grow to something more complicated I recommend replacing RegExp scanning with full-fledged parser/lexer using for example Jison "Your friendly JavaScript parser generator!" or anything else that suits you.

Javascript: Mutating "05/01/2013" into "20130501"?

So I have a string that represents a date and I need to change the format of it. This is what I have so far:
function myFunction()
{
var dateto = "05/01/2013";
dateto.replace("/", "");
//now what?
}
It will always originally be in the MM/DD/YYYY format, and I need to change it to a YYYYMMDD format. I'm looking for something on the lines of dateto = dateto[5..8] + dateto[0..1] + dateto[2..3]
. Not sure how to write that in JS though.
You can use some simple string maniuplation
var dateto = "05/01/2013";
var parts = dateto.split('/');
var newDate = parts[2] + parts[0] + parts[1];
Fiddle: http://jsfiddle.net/kvU6H/
This can be done using replace with a regular expression and capture groups:
"05/01/2013".replace(
/(\d{2})\/(\d{2})\/(\d{4})/, // capture data in groups
"$3$1$2") // replace with captured groups
While the above approach works well enough for this specific case, consider a library like moment.js:
moment
.parse("05/01/2013", "MM/DD/YYY") // parse our format
.format("YYYYMMDD") // write target format
You could consider the substring() function where you just provide the beginning and end positions (or indexes) of the desired string in the original string:
function myFunction()
{
var dateto = "05/01/2013";
return dateto.substring(6, 10) + dateto.substring(0, 2) + dateto.substring(3, 5);
}
returns:
20130501
Indexes start from 0 in Javascript (and most programming languages)... so for your string:
string: 0 5 / 0 1 / 2 0 1 3
index: 0 1 2 3 4 5 6 7 8 9

check input value for specific format using Javascript

I have an input field that allows a user to enter a date.
I need this date to be in the following format: 10Jan13 (capitalization is not important)
There is a popup calender that if used will format the date correctly for the user.
I'd like to check the value of the input onblur using Javascript to be sure that the user did not either paste or type the date improperly.
I am currently checking number-only fields like this:
var numbers = /^[0-9]+$/;
if (!BIDInput.value.match(numbers))
{
checkedInput.value = "";
alert('Not a number');
}
and I'm checking letters-only fields like this:
var letters = /^[a-z]+$/
if (!nameInput.value.match(letters))
{
nameInput.value = "";
alert('Not a letter');
}
I would like to check the date format in a similar a fashion if possible. But anything that accomplishes the task will do. Can anyone point me in the right direction on how to get this done?
I know that client side validation does not replace server side validation. This is for user experience purposes only.
You're pretty much there with what you have. Basically your format is one or two digits, then one of 12 possible strings, followed by two digits. So for instance:
var shortDateRex = /^\d{1,2}(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\d{2}$/;
Breakdown:
^ Start of string.
\d{1,2} One or two digits.
(:?...) A non-capturing group. Or you could use a capture group if you like.
Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec An alternation, allowing any of those twelve choices. Naturally you can add more if you like. If you have two choices that start the same way (Jan and January, for instance), put the longer one earlier in the alternation.
\d{2} Two digits.
Side note: I'd have to recommend against two-digit dates on principle, and particularly given where in the century we currently are!
Responding to Amberlamps' comment that this doesn't validate the date: Once you've validated the format, it's trivial to then check the date itself if you like (to rule out 30Feb13, for instance):
var validateDateString = (function() {
var monthNames = "Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec".toLowerCase().split("|");
var dateValidateRex = /^(\d{1,2})(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)(\d{2})$/i;
var arbitraryCenturyCutoff = 30;
function validateDateString(str) {
var match;
var day, month, year;
var dt;
match = dateValidateRex.exec(str);
if (!match) {
return false;
}
day = parseInt(match[1]);
month = monthNames.indexOf(match[2].toLowerCase()); // You may need a shim on very old browsers for Array#indexOf
year = parseInt(match[3], 10);
year += year > arbitraryCenturyCutoff ? 1900 : 2000;
dt = new Date(year, month, day);
if (dt.getDate() !== day ||
dt.getMonth() !== month ||
dt.getFullYear() !== year) {
// The input was invalid; we know because the date object
// had to adjust something
return false;
}
return true;
}
return validateDateString;
})();
...or something along those lines.
Live Example | Source
Or if (like me) you hate to see a list like that list of month names repeated you can use the RegExp constructor with a string instead, but you have to remember to duplicate your backslashes:
var monthNamesString = "Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec";
var monthNames = monthNamesString.toLowerCase().split("|");
var dateValidateRex = new RegExp("^(\\d{1,2})(" + monthNamesString + ")(\\d{2})$", "i");
Live Example | Source
You would use the following regular expression to check for a string starting with 2 numbers, followed by 3 characters followed by 2 numbers
[0-9]{2}[a-zA-Z]{3}[0-9]{2}

Categories

Resources