This might be a bit of a tricky one, I'm trying to come up with a regular expression to validate various given date intervals against the 8601 spec (https://en.wikipedia.org/wiki/ISO_8601#Durations). I have pretty much else all the cases working with the following regular expression:
^P(\d+(?:[,.]\d+)?Y)?(\d+(?:[,.]\d+)?M)?(\d+(?:[,.]\d+)?D)?(?:T(\d+(?:[,.]\d+)?H)?(\d+(?:[,.]\d+)?M)?(\d+(?:[,.]\d+)?S)?)?$
However the one place it falls down is in the aspect of the fractional unit only being allowed on the smallest supplied unit.
So for example:
P1DT1.5H is a valid string (The above regex technically allows this) P1.5DT1H is not a valid duration, as the hours are the smallest supplied unit. P1.5DT1.5H would also not be valid.
I've reached the end of my regex skills to try and figure out a way to incorporate this into the above. Anyone have any help or guidance on how this might be achived?
Assuming the fractional part can only appear if there are no more digits to the right, you can use
^P(?!.*\d[,.]\d.*\d)(?!$)(\d+(?:[,.]\d+)?Y)?(\d+(?:[,.]\d+)?M)?(\d+(?:[,.]\d+)?W)?(\d+(?:[,.]\d+)?D)?(T(?=\d)(\d+(?:[,.]\d+)?H)?(\d+(?:[,.]\d+)?M)?(\d+(?:[,.]\d+)?S)?)?$
See the regex demo.
The (?!.*\d[,.]\d.*\d) negative lookahead fails the match if there is a number with a fractional part followed with another number anywhere in the string.
You can learn more about the pattern used here in the Regex for ISO 8601 durations post.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With