Andres Zapata
Andres Zapata

Reputation: 1930

Javascript regex for validating 12 hour time

I'm trying to build a 12 hour input component in Javascript and I want to validate the format in real time, as the user types, like a parser validates incoming tokens.

I'm using react, so in each render the field value gets passed trhough the following regex:

const validTime = /(0[1-9])|(1[0-2]):([0-5][0-9])\s((a|p|A|P)(m|M))/;

I test if the value is valid, if not I add a red border to the input, but with this approach I can write anything, it wouldn't get submitted but you could write something like ajsjjsdf, and I'm looking for something different. Allow the user to type only the characters allowed by the regex rule above in real time.

Edit:

I'm adding some code...

Basically the input simpliefied is:

<input
  ref={(input) => {this[keyName] = input}}
  className="form-control"
  placeholder="09:00 AM"
  value={scheduleTime ? scheduleTime.value : ''}
  onChange={(ev) => this.onChangeTimeSchedule(ev, keyName)}/>

And the value handler:

  onChangeTimeSchedule = (ev, scheduleKey) => {
    const validChar = /[0-9]|[aApPmM]|[\s\b]|:/;
    const validTime = /(0[1-9])|(1[0-2]):([0-5][0-9])\s((a|p|A|P)(m|M))/;
    const { value } = ev.target;
    if(!validTime.test(value))
      return;

    const { schedule } = this.state;
    schedule[scheduleKey] = {value, invalid: false};
    this.setState({schedule});
  };

if I use validChar it would only allow the characters I want, but it would allow strings like 10:aaaM.

If I use validTime (this is the check I do for each render, to add a red border if invalid) in this context, I always returns false, because it excepts a full match: 10:0 is wrong, 10:00 PM is correct.

Upvotes: 0

Views: 1754

Answers (1)

user557597
user557597

Reputation:

This is one way to do it. Set it to case insensitive.

^(0(?:[1-9]|$)|1(?:[0-2]|$))(?:(:)(?:([0-5])(?:([0-9])(?:(\s)([ap]m?)?)?)?)?)?$

What you can get with this:

  • If group 5 length == 2 (am/pm) the entire time is finished.
  • Group 1 contains the partial or full valid data.
  • Group 2 contains the hours.
  • Group 3 and 4 contain the minute digits (join together).
  • Group 5 contains the am/pm.

There are 2 ways to use this regex.

  1. As a test for validity. If it does not match, put a red box around the
    edit box and let the user figure out the mistake.
  2. As a self correcting match:
    • Take off the last $ in the regex, allowing a partial match.
    • After every match, write back the group 1 (partial) to the edit box
      thus not allowing invalid entries.
      Wait for a submit button, then validate the entire string (start to finish).

Formatted / explained :

 ^                             # BOS
 (                             # (1 start)
      # Hours
      (                             # (2 start)
           0 
           (?: [1-9] | $ )
        |  1 
           (?: [0-2] | $ )
      )                             # (2 end)


      # Minutes
      (?:
           :                             # ':'
           (?:

                ( [0-5] )                     # (3), Min,digit 1
                (?:
                     ( [0-9] )                     # (4), Min,digit 2
                     (?:
                          \s                            # space
                          (                             # (5 start), AM / PM
                               [ap] m?
                          )?                            # (5 end)
                     )?
                )?

           )?
      )?
 )                             # (1 end)
 $                             # EOS

Upvotes: 1

Related Questions