From f5f8445ee7fae54a264c88e2d85b25b264e4b5ec Mon Sep 17 00:00:00 2001 From: Mark Probst Date: Mon, 7 Sep 2026 10:56:56 -0700 Subject: [PATCH 1/2] fix: validate native ISO date-times --- .../src/language/CPlusPlus/CPlusPlusRenderer.ts | 2 +- .../src/language/Objective-C/ObjectiveCRenderer.ts | 5 ++++- packages/quicktype-core/src/language/Php/PhpRenderer.ts | 8 ++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/quicktype-core/src/language/CPlusPlus/CPlusPlusRenderer.ts b/packages/quicktype-core/src/language/CPlusPlus/CPlusPlusRenderer.ts index ab8fce746e..5f51b96a09 100644 --- a/packages/quicktype-core/src/language/CPlusPlus/CPlusPlusRenderer.ts +++ b/packages/quicktype-core/src/language/CPlusPlus/CPlusPlusRenderer.ts @@ -1542,7 +1542,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { key, ") != j.end() && !std::regex_match(j.at(", key, - ').get(), std::regex("^[0-9]{4}-[0-9]{2}-[0-9]{2}T.*$"))) throw std::runtime_error("Expected date-time");', + ').get(), std::regex("^(?:(?:[0-9]{4}-(?:0[13578]|1[02])-(?:0[1-9]|[12][0-9]|3[01]))|(?:[0-9]{4}-(?:0[469]|11)-(?:0[1-9]|[12][0-9]|30))|(?:[0-9]{4}-02-(?:0[1-9]|1[0-9]|2[0-8]))|(?:(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:[02468][048]|[13579][26])00)-02-29))[Tt](?:[01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](?:[.][0-9]+)?(?:[Zz]|[+-](?:[01][0-9]|2[0-3]):[0-5][0-9])?$"))) throw std::runtime_error("Expected date-time");', ); } diff --git a/packages/quicktype-core/src/language/Objective-C/ObjectiveCRenderer.ts b/packages/quicktype-core/src/language/Objective-C/ObjectiveCRenderer.ts index eb970fda54..8d19dd50f5 100644 --- a/packages/quicktype-core/src/language/Objective-C/ObjectiveCRenderer.ts +++ b/packages/quicktype-core/src/language/Objective-C/ObjectiveCRenderer.ts @@ -936,7 +936,10 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { } if (property.type.kind === "date-time") { this.emitLine( - `if (dict[@"${objectiveCStringEscape(jsonName)}"] && [dict[@"${objectiveCStringEscape(jsonName)}"] rangeOfString:@"^[0-9]{4}-[0-9]{2}-[0-9]{2}T" options:NSRegularExpressionSearch].location == NSNotFound) return nil;`, + `if (dict[@"${objectiveCStringEscape(jsonName)}"] && [dict[@"${objectiveCStringEscape(jsonName)}"] rangeOfString:@"^[0-9]{4}-[0-9]{2}-[0-9]{2}[Tt](?:[01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](?:\\\\.[0-9]+)?(?:[Zz]|[+-](?:[01][0-9]|2[0-3]):[0-5][0-9])?$" options:NSRegularExpressionSearch].location == NSNotFound) return nil;`, + ); + this.emitLine( + `if (dict[@"${objectiveCStringEscape(jsonName)}"] && ![[[[NSISO8601DateFormatter new] stringFromDate:[[NSISO8601DateFormatter new] dateFromString:[[dict[@"${objectiveCStringEscape(jsonName)}"] substringToIndex:10] stringByAppendingString:@"T00:00:00Z"]]] substringToIndex:10] isEqualToString:[dict[@"${objectiveCStringEscape(jsonName)}"] substringToIndex:10]]) return nil;`, ); } if ( diff --git a/packages/quicktype-core/src/language/Php/PhpRenderer.ts b/packages/quicktype-core/src/language/Php/PhpRenderer.ts index f468f82635..4d3dde8097 100644 --- a/packages/quicktype-core/src/language/Php/PhpRenderer.ts +++ b/packages/quicktype-core/src/language/Php/PhpRenderer.ts @@ -798,6 +798,14 @@ export class PhpRenderer extends ConvenienceRenderer { (transformedStringType) => { if (transformedStringType.kind === "date-time") { this.emitLine("$tmp = ", "new DateTime(", args, ");"); + this.emitLine("$errors = DateTime::getLastErrors();"); + this.emitBlock( + "if ($errors && ($errors['warning_count'] || $errors['error_count']))", + () => + this.emitLine( + "throw new Exception('Invalid date-time');", + ), + ); this.transformDateTime(className, "", ["$tmp"]); this.emitLine("return $tmp;"); return; From 68cdb19f9e0860f0516125a1c5e82a0bda63db21 Mon Sep 17 00:00:00 2001 From: Mark Probst Date: Mon, 7 Sep 2026 17:48:29 -0700 Subject: [PATCH 2/2] Add native date-time validation coverage --- test/inputs/schema/date-time.12.fail.date-time.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 test/inputs/schema/date-time.12.fail.date-time.json diff --git a/test/inputs/schema/date-time.12.fail.date-time.json b/test/inputs/schema/date-time.12.fail.date-time.json new file mode 100644 index 0000000000..fe33668ae1 --- /dev/null +++ b/test/inputs/schema/date-time.12.fail.date-time.json @@ -0,0 +1,7 @@ +{ + "date": "1985-04-12", + "time": "23:20:50.52Z", + "date-time": "2023-00-15T12:00:00Z", + "union-array": ["1985-04-12", "23:20:50.52Z"], + "complex-union-array": ["2018-08-13T21:31:01+00:10", "foo", 123] +}