1

I've got a particular date and time format I'm trying to live filter in the text field so the users (ideally) can't enter a different format.

On the live filtering, I've been able to limit the characters they can enter, but no luck enforcing the pattern as they type. I know there must be some way to do this with raw JavaScript, I've tried looping over it but so far no luck.

The format that I'm using is dd/mm/yyyy hh:mm am|pm with the time section and leading 0s being optional. So 03/01/1982 3:14 PM would fit, but so would 3/1/1982 The pattern that I've devised (and tested at regex101) seems overly complicated, perhaps that's part of why I'm not having any luck.

Here is the JavaScript I have that works for controlling what can be input, though as stated it doesn't conform the input to the pattern:

<script type="text/javascript">

function format_date(e){

    var text = document.getElementById(e);
    var regex = /[^\d pam//:]/gi;
    text.value=text.value.replace(regex, "");

}

</script>

and the HTML field calling it:

<input type="text"  id="dob" name="dob" onKeyup="formate_date('dob')" onKeydown="format_date('dob')">

This seems to be the regex for the pattern I need, allowing for what is optional and accounting for missing leading zeros:

/^[\d]{1,2}\/[\d]{1,2}\/[\d]{4}(\s[\d]{1,2}:[\d]{1,2} (am|pm))?/gi

Can anyone point me to examples or docs that address this type of issue or help me understand what I'm missing? When I've tried including a loop in the function it either throws an error or doesn't enforce the pattern so I'm at a bit of a loss.

Thanks!

wp78de
  • 18,207
  • 7
  • 43
  • 71
Andy Lance
  • 91
  • 1
  • 8

1 Answers1

1

As hinted by Wiktor, it is not trivial to validate text input as it is typed, e.g. see this lengthy discussion for further insights.

However, it can be done.

I follow the approach to listen to the propertychange event to catch all input (directly from the keyboard or pasted text) to the input form field and validate the input in two steps:

  1. a preliminary input as it is typed: ensures the basic format and let only values of certain type pass

    I use this pattern:
    (\d{0,2}(?:\/\d{0,2}(?:\/\d{0,4})?)?)(?:\s\d{0,2}(?::\d{0,2}(?:\s([APap]?[Mm]?)?)?)?)?$

  2. accepted input: input is fully validated against the allowed date time format

    The next thing is you need a much more sophisticated regex to validate the date time entry. Drawing from

I came up with the following gargantuan pattern:

^(?:(?:31(\/|-|\.)(?:0?[13578]|1[02]))\1|(?:(?:29|30)(\/|-|\.)(?:0?[1,3-9]|1[0-2])\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(\/|-|\.)0?2\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/|-|\.)(?:(?:0?[1-9])|(?:1[0-2]))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})(?:(?: (0?[1-9]|1[012])(:[0-5]\d) [APap][Mm])|$)

Sample code:

var goodDateTime = /^(?:(?:31(\/|-|\.)(?:0?[13578]|1[02]))\1|(?:(?:29|30)(\/|-|\.)(?:0?[1,3-9]|1[0-2])\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(\/|-|\.)0?2\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/|-|\.)(?:(?:0?[1-9])|(?:1[0-2]))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})(?:(?: (0?[1-9]|1[012])(:[0-5]\d) [APap][Mm])|$)/;
var goodEntry = /^(\d{0,2}(?:\/\d{0,2}(?:\/\d{0,4})?)?)(?:\s\d{0,2}(?::\d{0,2}(?:\s([APap]?[mM]?)?)?)?)?$/;

$("input")
  .data("oldValue", "")
  .bind("input propertychange", function() {
var $this = $(this);
var newValue = $this.val();

if (!goodEntry.test(newValue))
    return $this.val($this.data("oldValue"));
if (goodDateTime.test(newValue))
    $this.removeClass("redborder");
else $this.addClass("redborder");

return $this.data("oldValue", newValue);
  });
  
.redborder { border: 1px solid red; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" />

The input box shows a red boarder if the current input is invalid.
Input like 03/01/1982 3:14 pm or 03/01/82 or 17/12/2017 is accepted (you can paste it too).

PS:

  • You may need to further validate the values (e.g. the allowed date range, etc).
  • I'd also recommend to separate date and time to two different fields to make the validation easier.
  • Furthermore, consider splitting the input into day, month, year, etc and test all individual parts.
wp78de
  • 18,207
  • 7
  • 43
  • 71