Rexact
Cheatsheet

Regex ISO 8601 duration (P1DT12H)

An ISO 8601 duration is written 'P3Y6M4DT12H30M5S': 'P', then years, months, days (Y M D), then 'T' and hours, minutes, seconds (H M S), in that order, or 'P2W' for weeks. At least one field is required, and 'T' must be followed by at least one field. The attempts I read make every field optional: moment.js accepts 'P', 'PT' and even 'PY' (empty number), iso8601-duration accepts 'P' and 'PT', isodate (Python) accepts 'PT' and weeks mixed with days. Here's a pattern built on the XML Schema grammar, with weeks alone, compared against those attempts.

/^P(?:(?:[0-9]+Y(?:[0-9]+M)?(?:[0-9]+D)?|[0-9]+M(?:[0-9]+D)?|[0-9]+D)(?:T(?:[0-9]+H(?:[0-9]+M)?(?:[0-9]+(?:\.[0-9]+)?S)?|[0-9]+M(?:[0-9]+(?:\.[0-9]+)?S)?|[0-9]+(?:\.[0-9]+)?S))?|T(?:[0-9]+H(?:[0-9]+M)?(?:[0-9]+(?:\.[0-9]+)?S)?|[0-9]+M(?:[0-9]+(?:\.[0-9]+)?S)?|[0-9]+(?:\.[0-9]+)?S)|[0-9]+W)$/
passes 36/36 cases

Comparison of existing patterns

SourcepatternScore on the corpusReDoS
moment.js — tous les champs facultatifs et nombres vides : « P », « PT », « PY » passent ; signes et virgules partout (« P-1,5Y ») ; semaines mêlées aux jours^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$27 / 36safe
iso8601-duration (npm) — non ancrée ; « P » et « PT » seuls passent, « xP1Dx » passe ; semaines mêlées aux joursP(?:(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(?:T(\d+(?:[\.,]\d+)?H)?(\d+(?:[\.,]\d+)?M)?(\d+(?:[\.,]\d+)?S)?)?)19 / 36undetermined
isodate (Python) — « P » seul refusé mais « PT » passe ; décimales sur tous les champs, semaines mêlées aux jours, signe accepté^(?<sign>[+-])?P(?!\b)(?<years>[0-9]+([,.][0-9]+)?Y)?(?<months>[0-9]+([,.][0-9]+)?M)?(?<weeks>[0-9]+([,.][0-9]+)?W)?(?<days>[0-9]+([,.][0-9]+)?D)?((?<separator>T)(?<hours>[0-9]+([,.][0-9]+)?H)?(?<minutes>[0-9]+([,.][0-9]+)?M)?(?<seconds>[0-9]+([,.][0-9]+)?S)?)?$31 / 36undetermined

Implementation

const re = new RegExp("^P(?:(?:[0-9]+Y(?:[0-9]+M)?(?:[0-9]+D)?|[0-9]+M(?:[0-9]+D)?|[0-9]+D)(?:T(?:[0-9]+H(?:[0-9]+M)?(?:[0-9]+(?:\\.[0-9]+)?S)?|[0-9]+M(?:[0-9]+(?:\\.[0-9]+)?S)?|[0-9]+(?:\\.[0-9]+)?S))?|T(?:[0-9]+H(?:[0-9]+M)?(?:[0-9]+(?:\\.[0-9]+)?S)?|[0-9]+M(?:[0-9]+(?:\\.[0-9]+)?S)?|[0-9]+(?:\\.[0-9]+)?S)|[0-9]+W)$", "");
re.test(input);

Limits

  • Valide seulement la FORME : aucun contrôle de plausibilité (« PT90M », « P99Y » sont acceptés) ni de cohérence calendaire ; une durée n'a pas de date de départ, « P1M » n'a donc pas de longueur fixe en jours.
  • Refusé volontairement : durée négative (« -P1D », absente d'ISO 8601-1:2004 mais admise par XML Schema), virgule décimale, décimale sur un champ autre que les secondes, semaines mêlées à d'autres champs (« P1W2D »), minuscules. Certaines bibliothèques (Java, moment.js) acceptent tout ou partie : ajustez le motif si vous les consommez.
  • ISO 8601 n'a pas été consultée (norme payante) : la grammaire retenue est celle de XML Schema 1.1 et de la RFC 3339, qui divergent sur « P1Y2D » (XML Schema l'accepte, la RFC ne l'écrit pas). La forme alternative « P0003-06-04T12:30:05 » n'est pas gérée.

Related pages