simplifying regex expression for timestamp I was wondering if it's possible to simplify this regex string (JS):
function validateDateString(date){
    const regex = /[0-1][0-9]-[0-3][0-9]-[0-9]{4} [0-2][0-9]:[0-5][0-9] [A|P][M]/; 
    return regex.test(date)
}

It is supposed to validate a string in the following format: MM-DD-YYYY hh:mm A
Some minor tips:

Add &quot;^&quot; and &quot;$&quot; to your regex to ensure your input string doesn't contain anything but a date
No brackets are needed around the [M] - A simple M means the same thing
Instead of checking for AM/PM with [A|P][M], keep the AM/PM characters together, like this: (AM|PM) - it makes it much more readable.
Since it's impossible to accurately test numeric ranges of a date-string in regex, I wouldn't even attempt it. If you really want to ensure the numbers fall into a valid range, do so after the fact, outside of the regex. Inside the regex, you can simply use \d to match any digit.

After applying these tips, you'll be left with a pretty simple regex that looks like this:
/^\d\d-\d\d-\d\d\d\d \d\d:\d\d (AM|PM)$/

As an aside, you might notice it's possible to remove a little repetition in the regex with \d{2} or \d{4}, but don't bother. There's not really a lot of repetition, and the {2}/{4} will just obfuscate what you're trying to accomplish here.
Depending on your use case, simply using the above regex might be good enough, but if you also want to ensure the numbers fall into a valid range, I would actually parse the numbers out of the date-string, feed them into Javascript's Date class, and verify the numbers using the date instance. Relying on the built-in Date class will help with edge cases, such as leap years. In the below code snippet I am assuming that these date-strings are in UTC


function validateDateString(dateStr) {
  const regex = /^(\d\d)-(\d\d)-(\d\d\d\d) (\d\d):(\d\d) (?:AM|PM)$/;
  const match = regex.exec(dateStr);
  if (!match) return false;

  const [month, day, year, hr, min] = match.slice(1).map(Number);
  const date = new Date(Date.UTC(year, month-1, day, hr, min));
  return (
    year === date.getUTCFullYear() &amp;&amp;
    month === date.getUTCMonth() + 1 &amp;&amp;
    day === date.getUTCDate() &amp;&amp;
    hr === date.getUTCHours() &amp;&amp;
    min === date.getUTCMinutes()
  );
}

console.assert(validateDateString('11-30-1999 12:34 AM'));
console.assert(!validateDateString('13-30-1999 12:34 AM'));
console.assert(!validateDateString('1x-30-1999 12:34 AM'));
console.log('Done')



The important thing to understanding how the above code snippet works, is to understand what happens when you give new Date() (or in this case, date.UTC()) a too-big number. If, for example, you passed in 5 for the hours and 70 for the minutes, then it'll normalize the values by moving an hour worth of time from the minutes to the hours, leaving it with 6 as the hours and 10 as the minutes.
Here's what this looks like in action:
&gt; const d = new Date(0, 0, 0, 5 /* hours */, 70 /* minutes */)
&gt; d.getHours()
6
&gt; d.getMinutes()
10

In the above example, it's easy enough to test that a numeric overflow happened, we just need to compare our input numbers with our outputs. We can quickly see that 5 !== 6 and 70 !== 10, so some sort of overflow must have happened, which means our date string was not valid. This is the same principle being used in the above code snippet - we just test each input with each output to ensure nothing overflowed.