From 6a4c43333f7e8b3d13ccde310e2e70ace9dd588c Mon Sep 17 00:00:00 2001 From: agammann <161159040+agammann@users.noreply.github.com> Date: Sun, 20 Sep 2026 15:07:16 -0700 Subject: [PATCH] fix: accept fractional seconds in ISO durations --- lib/types/string.js | 2 +- test/types/string.js | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/types/string.js b/lib/types/string.js index 77578d59..ceacf738 100755 --- a/lib/types/string.js +++ b/lib/types/string.js @@ -29,7 +29,7 @@ const internals = { withoutPrefix: /^[0-9a-f]+$/i }, ipRegex: ipRegex({ cidr: 'forbidden' }).regex, - isoDurationRegex: /^P(?!$)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?$/, + isoDurationRegex: /^P(?!$)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?$/, guidBrackets: { '{': '}', '[': ']', '(': ')', '': '' diff --git a/test/types/string.js b/test/types/string.js index 3d28056e..70d34b33 100755 --- a/test/types/string.js +++ b/test/types/string.js @@ -5756,6 +5756,14 @@ describe('string', () => { describe('isoDuration()', () => { + it('rejects malformed fractional seconds', () => { + + const schema = Joi.string().isoDuration(); + for (const value of ['PT.5S', 'PT,5S', 'PT5.S', 'PT5,S', 'PT5.1.2S', 'PT5,1,2S', 'PT5.1S2M']) { + expect(schema.validate(value).error).to.be.an.error(); + } + }); + it('validates isoDuration', () => { Helper.validate(Joi.string().isoDuration(), [ @@ -5768,6 +5776,10 @@ describe('string', () => { ['P6M4DT12H30M5S', true], ['PT10H20M5S', true], ['PT40S', true], + ['PT4.4S', true], + ['PT4,4S', true], + ['PT0.001S', true], + ['P3Y6M4DT12H30M5.125S', true], ['PT0S', true], ['P0D', true], ['P30S', false, {