I'm working on an assignment for school where we're working with JavaScript (I'm only allowed to use JavaScript) to validate a form for a payment page. It's my first time working with JavaScript so and I feel a bit lost...
I'm faced with a task to validate the expiry date and the requirements are:
the number needs to be exactly 2-2 digits (in the format mm-yy)
mm needs to be >01 and <12
and the expiry date needs to be after today's date
So far I've only been able to specify the first two requirements and I have trouble figuring out how to check the date against today's date.
html
<form>
<label for="expiryDate">Expiry Date</label>
<input type="text" name="expiryDate" id="expiryDate" />
<input type="submit" value="Check out" />
</form>
JavaScript
var expiryDate = document.getElementById("expiryDate").value;
if (!expiryDate.match(/^[0][1-9]|[1][0-2]-[0-9]{2}$/)){
errMsg = errMsg + "The expiry date needs to be mm-yy and consist of a valid date.\n";
result = false;
}
So if anyone has an idea of how to help me, I would appreciate it!
I'm always surprised at how programmers would rather spend their efforts building straight-jackets for users rather than writing user friendly code.
The month criteria seem to be incorrect, ">01 and <12" infers a value from 2 to 11 inclusive, I expect that ">=1 and <=12" was intended.
To do exactly what the assignment requires, you could do something like:
/* Check that the provided string is:
** - exactly 2-2 digits in the format mm-yy
** - mm is >= 01 and <= 12
** - expiry date is this month or later
*/
function validateExpiryDate(s) {
// Check 2-2 digits
if (!/\d\d-\d\d/.test(s)) {
return 'Expiry date format must be MM-YY: ' + s;
}
// Check month is 1 to 12 inclusive
var b = s.split('-');
if (b[0]<1 || b[0]>12) {
return 'Expiry month must be from 00 to 12: ' + b[0];
}
// Check is this month or later
var d = new Date()
var c = d.getFullYear()/100 | 0 + '';
if (new Date(c + b[1], b[0], 1) < d) {
return 'Expiry date must be this month or later: ' + s;
}
return true;
}
// Some tests
['01-17','12-17','foo','13-20','9-18'].forEach(function(s){
console.log(validateExpiryDate(s));
})
However, to be a little more user friendly, you can accept single digits and various separators quite easily. Also, you can just cut to the chase and test whether the value entered generates a suitable expiry date. You can also reformat the entered string into the required format, e.g.:
// Validate expiry date in m-yy format
// Separator can be any non-digit
function checkExpiryDate(s) {
var b = s.split(/\D/);
var d = new Date();
var century = d.getFullYear()/100 | 0;
// Generate date for first day of following month
var expires = new Date(century + b[1], b[0], 1);
return d < expires;
}
// Reformat date in m/yy format to mm-yy strict
function formatExpiry(s) {
var b = s.split(/\D/);
function z(n){return (n<10?'0':'') + +n}
return z(b[0]) + '-' + z(b[1]);
}
['1/1','4-17','03-17','3-18','06/19','3.19','foo'].forEach(function(s) {
console.log('String "' + s + '" converts to "' +
formatExpiry(s) + '" and is ' +
(checkExpiryDate(s)? '' : 'not ') + 'valid.');
});
So being user friendly is also less code to write. ;-)
Calculating the century is a bit of overkill, you could just use "20" and expect that your code will not be running in 2095 when expiry dates will start having centuries of "21".
Something like this should help
var today = new Date(); // gets the current date
var today_mm = today.getMonth() + 1; // extracts the month portion
var today_yy = today.getFullYear() % 100; // extracts the year portion and changes it from yyyy to yy format
if(today_mm < 10) { // if today's month is less than 10
today_mm = '0' + today_mm // prefix it with a '0' to make it 2 digits
}
var mm = expiryDate.substring(0, 2); // get the mm portion of the expiryDate (first two characters)
var yy = expiryDate.substring(3); // get the yy portion of the expiryDate (from index 3 to end)
if (yy > today_yy || (yy == today_yy && mm >= today_mm)) {
// all good because the yy from expiryDate is greater than the current yy
// or if the yy from expiryDate is the same as the current yy but the mm
// from expiryDate is greater than the current mm
}
else
{
errMsg = errMsg + "The expiry date needs to be greater than today.\n";
result = false;
}
Related
I have an interface where I receive a date in this format: Month/Year, ex: 11/2022.
I would like to verify that this is a valid date.
I use the datatables editor. The configuration (see below) of the field works well, but since the user can enter the date himself without going through the calendar, there is a risk that the date entered is incorrect. It doesn't work like an input mask. So i need to validate the date in the code.
{
type: "datetime",
label: "Date:",
name: "Date",
def: function () { return new Date(); },
format: 'MM/YYYY',
fieldInfo: 'Format: Month/Year (ex: 12/2022)',
keyInput: true
}
The date should not be accepted if the difference between this date and today's date is less than 3 months.
It means that, compared to today, all dates before July will have to be rejected.
Currently I can do this with the relativedelta method of the python dateutil module. But as the validation must be done on the client side, I would like to do this in javascript (which I know very little).
The example below shows how to do this. You should take advantage of the HTML 5 input types to validate your dates. You also need to calculate 3 months from now in myEpoch and then compare it to the date/time given
HTML:
<p>
Date & Time: <input id="foo" type="datetime-local" />
</p>
JavaScript:
var myEpoch = new Date();
myEpoch.setMonth(myEpoch.getMonth() + 3);
myEpoch = myEpoch.getTime();
var foo = document.getElementById("foo");
if (foo.value < myEpoch) {
//show a message saying this date is invalid
}
Since user is entering date in MM/yyyy format, so i'm assuming that you take 1 as a date into account, i.e., if input is 03/2020, you would consider it as: 01/03/2020. Right? If
so, then you can do the following to validate this date:-
function isValidDate(inputDate) {
// Unfortunately JS doesn't have any in-built function to validate date in MM/yyyy format. Hence regex comes to the rescue
var regex = /^([0-9]{1,2})\/([0-9]{4,4})$/;
var matches = regex.exec(inputDate);
if (!matches || matches.length != 3) {
throw new Error('Please provide date in MM/yyyy format');
}
var inputMonth = matches[1]; // Return month from input date
var inputYear = matches[2]; // Return year from input date
var finalDate = inputMonth+ '/01/' + inputYear;
// Check if entered date is valid or not
var parsedDate = Date.parse(finalDate);
if (isNaN(parsedDate)) {
throw new Error('Unable to parse date.');
}
// Check if it is less than 3 months or not.
var isValid = !isLessThan3Months(new Date(finalDate), new Date());
return isValid;
}
function isLessThan3Months(dateToCompare, currentDate) {
var diffYears = currentDate.getFullYear() - dateToCompare.getFullYear();
var diffMonths = currentDate.getMonth() - dateToCompare.getMonth();
var diffDays = currentDate.getDate() - dateToCompare.getDate();
var months = diffYears * 12 + diffMonths;
if (diffDays > 0) {
months += '.' + diffDays;
} else if (diffDays < 0) {
months--;
months +=
'.' +
(new Date(currentDate.getFullYear(), currentDate.getMonth(), 0).getDate() + diffDays);
}
return months < 3;
}
isValidDate('03/2020');
So now, by calling isValidDate with user's input date in MM/yyyy format, you should be able to check if it is valid or not.
For this, you won't need to use any third party javascript library. Just plain javascript is enough.
You should probably use Moment.js, because working with the raw Date object is fiddly.
If you would rather use plain JavaScript, then the following might be of use:
const moreThan3MonthsHence = ({ utcYear, utcMonth },
now = new Date,
target = new Date(Date.UTC(utcYear, utcMonth)),
threeMonthsHence = addMonths(new Date(now.valueOf()), 3)) =>
(target > threeMonthsHence)
const validate = (str,
[utcMonth, utcYear] = str.split('/'),
date = new Date(Date.UTC(+utcYear, (+utcMonth)-1))) =>
moreThan3MonthsHence({ utcYear: date.getUTCFullYear(), utcMonth: date.getUTCMonth() })
const addMonths = (date, months, d = date.getDate()) => {
date.setMonth(date.getMonth() + +months);
// If rolled over to next month, set to last day of previous month
if (date.getDate() != d) {
date.setDate(0);
}
return date;
}
// Note: input is one-based months
console.log(validate('07/2020')) // true
console.log(validate('06/2020')) // false
console.log(validate('12/2019')) // false
Notes
now is internally represented as the milliseconds since the Unix epoch. Note this includes the current time of day.
target is the milliseconds since the Unix epoch of midnight on the supplied UTC date.
threeMonthsHence is the milliseconds since the Unix epoch of now (including time of day), plus three months.
validate parses the input string.
addMonths is necessary because the built-in function can roll-over into a new month with unexpected behavior.
Finally to solve my problem I mixed the solutions proposed by #Sumit Parakh and #ControlAltDel.
function isValidDate(inputDate) {
var regex = /^([0-9]{1,2})\/([0-9]{4,4})$/;
var matches = regex.exec(inputDate);
var parsedDate = 0;
if (!matches || matches.length != 3) {
throw new Error('Please provide date in MM/yyyy format');
}
else {
var inputMonth = matches[1]; // Return month from input date
var inputYear = matches[2]; // Return year from input date
var finalDate = inputMonth+ '/01/' + inputYear;
// Check if entered date is valid or not
var parsedDate = Date.parse(finalDate);
if (isNaN(parsedDate)) {
parsedDate = 0;
//throw new Error('Unable to parse date.');
}
return parsedDate;
}
var myEpoch = new Date();
myEpoch.setMonth(myEpoch.getMonth() + 3);
myEpoch = myEpoch.getTime();
finalDate = isValidDate(date_peremption.val());
if (finalDate == 0){
date_received.error("This date is invalid");
}
else if(finalDate < myEpoch) {
date_received.error("The date must be more than three months last");
}
It's not very elegant, but it works. Thanks everyone
I am having an input date field in my form. In my date field
i need to alert an error if the input date is greater than any date i define before
here is what i code :
$(document).ready(function () {
var date = new Date(2016,2,1); //the defined date is 1 March 2016
var day = date.getDate();
var month = date.getMonth();
month = month + 1;
if(day < 10){
day = '0' + day;
}
if(month < 10){
month='0'+month;
}
someday = day + '/' + month + '/' + date.getFullYear();
$("#q1 input").blur(function(){ //#q1 is the ID for the input field.
if($('#q1 input').val() > someday){
alert('the input is bigger than the defined');
}else{
alert('the defined is bigger than the input ');
}
});
});
To compare Dates is very straight forward. Most operators coerce the operands to number, and Dates return their time value so to see if today is before or after say 1 March 2016, create two Dates and compare them:
var epoch = new Date(2016,2,1); // Create date for 2016-03-01T00:00:00
var now = new Date(); // Create a date for the current instant
now.setHours(0,0,0,0); // Set time to 00:00:00.000
if (now < epoch) {
alert('Before 1 March, 2016');
} else {
alert('On or after 1 March, 2016');
}
Or a bit more compact:
alert((now < epoch? 'Before':'On or after') + ' 1 March, 2016');
You might want to compare the values as in the date form, not the way you did.
Convert the input value into the form of date and compare it with the variable 'date'.
Compare the input date with the desired date that you defined. For example:
var d1 = new Date();
var d2 = new Date(d1);
var same = d1.getTime() === d2.getTime();
var notSame = d1.getTime() !== d2.getTime();
If you find it tricky, then there is an awesome js library called moment.js. It is very useful when playing with dates.
$(document).ready(function () {
var date=new Date(2016,2,1); //the defined date is 1 March 2016
var fixedDate = returnDate(date);// convert date in dd/mm/yyyy format
//#q1 input will search a child input inside an #q1 dom element, which probably not the case
// input#q1 will refer to input with id #q1
// You can directly query the input since it has id #q1 so #q1 input is not correct
$("#q1").blur(function(){ //#q1 is the ID for the input field.
var d2 = new Date($('#q1').val());
var inputDate = returnDate(d2); // convert input date in dd/mm/yyyy format
if(inputDate > fixedDate){ // compare two dates
console.log('the input is bigger than the defined');
}else{
console.log('the defined is bigger than the input ');
}
});
});
// Write a general function to convert date in dd/mm/yyyy format
function returnDate(date){
var day=date.getDate();
var month=date.getMonth();
month=month+1;
if(day<10){
day='0'+day;
}
if(month<10){
month='0'+month;
}
var someday=day+ '/' + month + '/' + date.getFullYear();
return someday;
}
JSFIDDLE
EDIT 1
Use ternary operator instead of if-else
inputDate > fixedDate? (console.log("the input is bigger than the defined")):(console.log("the defined is bigger than the input"))
with ternary operator
I have a simple code that echos the current Hour+Minute+Date as one number sequence.
I need to add 1 to all the numbers outputted, individually.
Example: If the current time and date is: 22321512 then i need jQuery to output: 33432623.
My knowledge in jQuery is pretty slim, How can this be achieved?
HTML:
<span id="date"></span>
Code:
var now = dateFormat(new Date(), "HHMMddmm");
$('#date').append(now);
You need to do the following roughly:
var currentDate = new Date();
var myDate = new Date(currentDate.getYear() + 1, currentDate.getMonth() + 1, currentDate.getDay() + 1);
alert(myDate.getTime());
Should solve your problem.
If you want to merely increment each unit by 1 and let the JavaScript engine advance the date and time on overflow, then Captain John's answer will work perfectly.
This means that, for example, if this routine were to be run at 11:59 PM on December 31, your output would be 00000100.
If you want each unit to be incremented by 1 without the date being advanced, you will have to stop relying on Steven Levithan's [excellent] dateFormat library and do it yourself:
var now = new Date(),
hours = now.getHours() + 1, // add 1 hour
minutes = now.getMinutes() + 1, // add 1 minute
date = now.getDate() + 1, // add 1 day
month = now.getMonth() + 1, // add 1 month
padLeft = function (val) { // make a formatter
while (val.length < 2) {
val = '0' + val; // string is less than 2 characters, pad left side with '0'
}
return val; // return formatted string
},
formatted = padLeft(hours) + padLeft(minutes) + padLeft(date) + padLeft(month);
$('#date').append(formatted);
Getting number length as string you can easily sum 1 to each number.
The result is given as timestamp
To get Date object, use new Date(result);
var now = new Date().getTime(); // 22321512 on your example
// Answer
var result = 0;
var str = now.toString();
for(var i = 0; i < str.length; i++) {
result += Math.pow(10, i);
}
result += now; // Ex.: 22321512 + 11111111
I'm looking to implement validation for a mobile site, where I have two input fields and I would like the first to validate the value is no later than todays date, and the second to validate it is no later than a one year in advance of the first value.
E.g
First Value = 26/11/2013
Second Value can not contain a value later than 26/11/2014
Is this possible?
I like moment.js. It makes it easier to deal with dates and times.
First, let's make sure a day "is before tomorrow". This will depend a bit upon what the definition of tomorrow is.
var m = moment("26/11/2013", "MM/DD/YYYY");
// tomorrow this time
var t = moment().add("days", 1);
// tomorrow start of day
var tomorrow = moment([t.year(), t.month(), t.date()]);
if (m.lessThan(tomorrow)) {
// today!!! (or before)
}
Similarly, the same approach can be used for a year from now. It's likely fine enough to not care about the time component in this case, and I've slogged on another day - but if it matters (e.g. looking for the start of the day), see the previous example.
var m = moment("26/11/2013", "MM/DD/YYYY");
var aYearFromNow = moment().add("years", 1).add("days", 1);
if (m.lessThan(aYearFromNow)) {
// still less than a year!
}
1) cache the elements.
var d1 = document.getElementById('date1');
var d2 = document.getElementById('date2');
2) The value of d1 and d2 are string data type. So split them and parse it to date format as below
var t = d1.value.split("-");
var date = new Date(parseInt(t[0], 10) + 1, parseInt(t[1], 10), t[2]);
Here the year is incremented by 1, based on the value in d1.
4) Again parse it back to string format (YYYY-MM-DD)
var maxi = date.getFullYear() + "-" + date.getMonth() + "-" + date.getDate();
5) Set this as value for max attribute for d2
d2.setAttribute("max", maxi);
Finally add the below method to onblur event of d1.
function setMaxDate() {
var d1 = document.getElementById('date1');
var d2 = document.getElementById('date2');
var t = d1.value.split("-");
var date = new Date(parseInt(t[0], 10) + 1, parseInt(t[1], 10), t[2]);
var maxi = date.getFullYear() + "-" + date.getMonth() + "-" + date.getDate();
d2.setAttribute("max", maxi);
}
JSFiddle
Better with javascript. You can I use HTML5 attribute type="date" but keep in mind it's barely supported.
You can use a Regex pattern like this /([0-9]{2})/([0-9]{2})/([0-9]{4})/, that is, two decimal digits, a slash, two more decimal digits, a slash and four decimal digits, everything grouped separately (group 1 = day, group 2 = month, group 3 = year). You would test for this pattern in a event, (I would suggest onchange, since you mentioned mobile) and also check if the numbers are within a valid range (e.g. day < 32, month < 13, year < currentYear-1).
Javascript definitely isn't my strongest point. I've been attempting this for a couple of hours now and seem to be getting stuck with date formatting somewhere.
I have a form where a user selected a date (dd/mm/yyyy) and then this date will be taken and 2 weeks will be added to it and then date will be copied to another form field.
My latest attempt below isn't even adding a date yet just copying the selected date in one form field to another, if I select '03/02/2012', it outputs 'Fri Mar 02 2012 00:00:00 GMT+0000 (GMT Standard Time)', so its outputting in American format as well as the full date. How to I get it to out put in the same format and add 2 weeks?
function LicenceToOccupy(acceptCompletionDate)
{
var date1 = new Date(acceptCompletionDate);
document.frmAccept.acceptLicence.value = date1;
}
You can do this :
const numWeeks = 2;
const now = new Date();
now.setDate(now.getDate() + numWeeks * 7);
or as a function
const addWeeksToDate = (dateObj,numberOfWeeks) => {
dateObj.setDate(dateObj.getDate()+ numberOfWeeks * 7);
return dateObj;
}
const numberOfWeeks = 2
console.log(addWeeksToDate(new Date(), 2).toISOString());
You can see the fiddle here.
According to the documentation in MDN
The setDate() method sets the day of the Date object relative to the beginning of the currently set month.
This might not answer the question per se, but one can find a solution with these formulas.
6.048e+8 = 1 week in milliseconds
Date.now() = Now in milliseconds
Date.now() + 6.048e+8 = 1 week from today
Date.now() + (6.048e+8 * 2) = 2 weeks from today
new Date( Date.now() + (6.048e+8 * 2) ) = Date Object for 2 weeks from today
You're assigning date1 to be a Date object which represents the string you pass it. What you're seeing in the acceptLicense value is the toString() representation of the date object (try alert(date1.toString()) to see this).
To output as you want, you'll have to use string concatenation and the various Date methods.
var formattedDate = date1.getDate() + '/' + (date1.getMonth() + 1) + '/' + date1.getFullYear();
In terms of adding 2 weeks, you should add 14 days to the current date;
date1.setDate(date.getDate() + 14);
... this will automatically handle the month increase etc.
In the end, you'll end up with;
var date1 = new Date(acceptCompletionDate);
date1.setDate(date1.getDate() + 14);
document.frmAccept.acceptLicence.value = date1.getDate() + '/' + (date1.getMonth() + 1) + '/' + date1.getFullYear();
N.B Months in JavaScript are 0-indexed (Jan = 0, Dec = 11), hence the +1 on the month.
Edit: To address your comment, you should construct date as follows instead, as the Date argument is supposed to be "A string representing an RFC2822 or ISO 8601 date." (see here).
var segments = acceptCompletionDate.split("/");
var date1 = new Date(segments[2], segments[1], segments[0]);
This should do what you're looking for.
function LicenceToOccupy(acceptCompletionDate)
{
var date1 = new Date(acceptCompletionDate);
date1.setDate(date1.getDate() + 14);
document.frmAccept.acceptLicence.value = date1.getDate() + '/' + (date1.getMonth() + 1) + '/' + date1.getFullYear();
}
To parse the specific dd/mm/yyyy format and increment days with 14 , you can do something like split the parts, and create the date object with y/m/d given specfically. (incrementing the days right away) Providing the separator is always -, the following should work:
function LicenceToOccupy(acceptCompletionDate)
{
var parts = acceptCompletionDate.split("/");
var date1 = new Date(parts[2], (parts[1] - 1), parseInt(parts[0]) + 14); //month 0 based, day: parse to int and increment 14 (2 weeks)
document.frmAccept.acceptLicence.value = date1.toLocaleDateString(); //if the d/m/y format is the local string, otherwise some cusom formatting needs to be done
}
date1.toLocaleDateString()
Thiswill return you date1 as a String in the client convention
To create a new date date2 with 2 weeks more (2weeks = 27246060 seconds):
var date2 = new Date(date1 + 60*60*24*7*2);