Regex to Match ISO 8601 Duration Format

Validate ISO 8601 duration strings like P1Y2M3DT4H5M6S. Matches period designators for years, months, weeks, days, hours, minutes, and seconds.

Regular Expression

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

Token Breakdown

TokenDescription
^Anchors at the start of the string (or line in multiline mode)
PMatches the literal character 'P'
(?!Start of negative lookahead assertion
$Anchors at the end of the string (or line in multiline mode)
)End of group
(Start of capturing group
\dMatches any digit (0-9)
+Matches the preceding element one or more times (greedy)
YMatches the literal character 'Y'
)End of group
?Makes the preceding element optional (zero or one times)
(Start of capturing group
\dMatches any digit (0-9)
+Matches the preceding element one or more times (greedy)
MMatches the literal character 'M'
)End of group
?Makes the preceding element optional (zero or one times)
(Start of capturing group
\dMatches any digit (0-9)
+Matches the preceding element one or more times (greedy)
WMatches the literal character 'W'
)End of group
?Makes the preceding element optional (zero or one times)
(Start of capturing group
\dMatches any digit (0-9)
+Matches the preceding element one or more times (greedy)
DMatches the literal character 'D'
)End of group
?Makes the preceding element optional (zero or one times)
(?:Start of non-capturing group
TMatches the literal character 'T'
(?!Start of negative lookahead assertion
$Anchors at the end of the string (or line in multiline mode)
)End of group
(Start of capturing group
\dMatches any digit (0-9)
+Matches the preceding element one or more times (greedy)
HMatches the literal character 'H'
)End of group
?Makes the preceding element optional (zero or one times)
(Start of capturing group
\dMatches any digit (0-9)
+Matches the preceding element one or more times (greedy)
MMatches the literal character 'M'
)End of group
?Makes the preceding element optional (zero or one times)
(Start of capturing group
\dMatches any digit (0-9)
+Matches the preceding element one or more times (greedy)
(?:Start of non-capturing group
\.Matches a literal dot
\dMatches any digit (0-9)
+Matches the preceding element one or more times (greedy)
)End of group
?Makes the preceding element optional (zero or one times)
SMatches the literal character 'S'
)End of group
?Makes the preceding element optional (zero or one times)
)End of group
?Makes the preceding element optional (zero or one times)
$Anchors at the end of the string (or line in multiline mode)

Detailed Explanation

This regex validates ISO 8601 duration format strings. Here is the token-by-token breakdown:

^ — Anchors the match at the start of the string.

P — Matches the literal P (period) character that begins every ISO 8601 duration. This is mandatory and stands for period.

(?!$) — A negative lookahead ensuring the string does not end immediately after P. A bare P is not a valid duration.

(\d+Y)? — Optional capturing group 1 matches the years component: one or more digits followed by Y.

(\d+M)? — Optional capturing group 2 matches the months component: digits followed by M.

(\d+W)? — Optional capturing group 3 matches the weeks component: digits followed by W.

(\d+D)? — Optional capturing group 4 matches the days component: digits followed by D.

(?:T(?!$) — An optional non-capturing group for the time portion, starting with the literal T time designator. The negative lookahead (?!$) ensures T is not the last character.

(\d+H)? — Optional capturing group 5 matches hours: digits followed by H.

(\d+M)? — Optional capturing group 6 matches minutes in the time section: digits followed by M.

(\d+(?:.\d+)?S)? — Optional capturing group 7 matches seconds: digits with an optional decimal fraction followed by S.

)? — Makes the entire time section optional.

$ — Anchors at the end of the string.

ISO 8601 durations are used in APIs, scheduling systems, video metadata, and configuration files. Examples include P1Y (one year), PT1H30M (1 hour 30 minutes), and P2DT12H (2 days 12 hours).

Example Test Strings

InputExpected
P1Y2M3DT4H5M6SMatch
PT1H30MMatch
P1DMatch
PNo Match
1Y2MNo Match
P3WMatch

Try It — Interactive Tester

//
gimsuy
No matches found.
Pattern: 78 charsFlags: noneMatches: 0

Ctrl+Shift+C to copy regex

Customize this pattern →