1

I have an interface where I receive a date in this format: Month/Year, ex: 11/2022.

  1. 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
}
  1. 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).

Tobin
  • 2,029
  • 2
  • 11
  • 19
  • Can the date be in the future and the past by 3 months? For example, today is 3/3/2020. what's the earliest month and latest month that can be inputted? – Lonnie Best Mar 03 '20 at 14:52
  • @LonnieBest In my case the earliest date is today's date. It does not need to be entered. The latest date must be greater than the first by at least 3 months. – Tobin Mar 03 '20 at 15:27
  • Ok, well I've edited my answer to those specifications. It is a different approach to the problem, though. Basically, why not just put the valid months in a drop down menu, since there are only 3? – Lonnie Best Mar 03 '20 at 15:37

4 Answers4

1

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
}
ControlAltDel
  • 33,923
  • 10
  • 53
  • 80
  • By testing this code I get the error: `Uncaught TypeError: myEpoch.setMonths is not a function` – Tobin Mar 03 '20 at 14:41
  • @Tobin I fixed it – ControlAltDel Mar 03 '20 at 15:10
  • I can recover the Epoch time. But where I'm stuck is that I don't know how to customize the date field which is generated by datatables. So I have to convert the entered date (ex: `06/2020`) into epoch time. do you have an idea? – Tobin Mar 03 '20 at 15:42
  • @Tobin I think the way to do it is to convert the datatables date into a Javascript / computer date: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date then use that date value to set the input value – ControlAltDel Mar 03 '20 at 15:53
1

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.

Ben Aston
  • 53,718
  • 65
  • 205
  • 331
1

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.

Sumit Parakh
  • 1,098
  • 9
  • 19
0

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

Tobin
  • 2,029
  • 2
  • 11
  • 19