I am trying to validate, with a RegEx, a user input to a date/time field in the following format: yyyy-mm-dd HH:mm
. Since a user would type this one character at a time, the RegEx also needs to allow for all the substrings (e.g., yyyy-mm
, yyyy-mm-dd H
, etc.).
For example, the following date 2022-01-29 11:59
or any substring of it, such as (empty string), 202
, 2022-01-
, 2022-01-29
, etc. should match.
Strings like 2022-13
, 222-
or 2024-01-01 23:111
should not match.
I am trying something like,
[0-9]{4}?-?(0[1-9]|1[0-2])-?(0[1-9]|[1-2][0-9]|3[0-1])? ?(2[0-3]|[01][0-9])?:?[0-5]?[0-9]?$
making every character optional, but it does not work since it can just skip parts of the string, e.g. 2022-29
returns match...
CodePudding user response:
It becomes a bit convoluted if you want to match number ranges properly as you type. Here is a regex solution with test cases that has many nested groups (to allow partial input) and validates the ranges of month, day, hours, and minutes:
const regex = /^([0-9]{0,3}|[0-9]{4}(-([01]|(0[1-9]|1[0-2])(-([0-3]|(0[1-9]|[12][0-9]|3[01])( ([0-2]|([0-1][0-9]|2[0-3])(:([0-5]|([0-4][0-9]|5[0-9]))?)?)?)?)?)?)?)?)$/;
[
'',
'2',
'20',
'202',
'2022',
'2022-',
'2022-0',
'2022-01',
'2022-01-',
'2022-01-2',
'2022-01-29',
'2022-01-29 ',
'2022-01-29 1',
'2022-01-29 11',
'2022-01-29 11:',
'2022-01-29 11:5',
'2022-01-29 11:59',
'202-01',
'2022-1-1',
'2022-13',
'2022-01-32',
'2024-01-01 24',
'2024-01-01 01:60',
'2024-01-01 23:111'
].forEach(str => console.log(str, '=>', regex.test(str)));
Output:
=> true
2 => true
20 => true
202 => true
2022 => true
2022- => true
2022-0 => true
2022-01 => true
2022-01- => true
2022-01-2 => true
2022-01-29 => true
2022-01-29 => true
2022-01-29 1 => true
2022-01-29 11 => true
2022-01-29 11: => true
2022-01-29 11:5 => true
2022-01-29 11:59 => true
202-01 => false
2022-1-1 => false
2022-13 => false
2022-01-32 => false
2024-01-01 24 => false
2024-01-01 01:60 => false
2024-01-01 23:111 => false
Hierarchy of regex:
^(
-- start of string & group[0-9]{0,3}
-- 0 to 3 digits for partial year
|
-- logical or[0-9]{4}
--(
---
-- dash(
--[01]
-- one digit of month
|
-- logical or(0[1-9]|1[0-2])
-- two digits of month(
---
-- dash(
--[0-3]
-- one digit of day
|
-- logical or(0[1-9]|[12][0-9]|3[01])
-- two digits of day(
--(
--[0-2]
-- one digit of hours
|
-- logical or([0-1][0-9]|2[0-3])
-- two digits of hours(
--:
-- colon(
--[0-5]
-- one digit of minutes
|
-- logical or([0-4][0-9]|5[0-9])
-- two digits of minutes
)?
--
)?
--
)?
--
)?
--
)?
--
)?
--
)?
--
)?
--
)$
-- end of string and group
Learn more about regex: https://twiki.org/cgi-bin/view/Codev/TWikiPresentation2018x10x14Regex