Regular expression for ISO 8601 duration

I need a regular expression to check the duration in ISO 8601 format (except for the fractional parts that I don't need).

PnYnMnDTnHnMnS

PNW

Here is what I have:

^P(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(\d+H)?(\d+M)?(\d+S)?)?$ 

The only problem is that strings with constants P and PT allowed with this regex, since all parts are "zero or one" ? .

  • There must be at least one component (date or time)
  • If T exists, then there must be a time component (H, M or S)
  • If T exists, then there may or may not be any date components (Y, M, or D)
  • Overflow allowed (e.g. P72H is basically equivalent to P3D )

Valid inputs:

 P1Y // date component only P2MT30M // date and time components PT6H // time component only P5W // another date component 

Inappropriate Inputs:

 P // no components PT // no components P3MT // T specified but not time components 

Invalid strings are currently being tested on the client side, but do not work on the server side, because they are passed to DateInteval , d as a failure on the client side, if possible. If everyone used Chrome 40+, I could point minlength='3' to the input element to help, but unfortunately this is not the case.

+6
source share
1 answer

If you have almost all the parts of your choice, but want to make sure that there is something else after P or T , you can use the options:

 ^P(?=\d+[YMWD])(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(?=\d+[HMS])(\d+H)?(\d+M)?(\d+S)?)?$ ^^^^^^^^^^^^ ^^^^^^^^^^^^ 

They require a sequence of numbers followed by a letter from the specified set in order to appear immediately after the previous pattern.

Watch the demo

UPDATE

If P can be "empty", use

 ^P(?!$)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(?=\d+[HMS])(\d+H)?(\d+M)?(\d+S)?)?$ 

Watch another demo . Here (?!$) Ensures that the string is not equal to P , and some other characters should be on the right.

Or, as @UlugbekUmirov suggests, it’s enough to just use T(?=\d) (since all additional parts begin with a digit):

 ^P(?!$)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?$ 
+8
source

All Articles