From 669e4eeb9cf9730e98c925eea4c8bef27a950b57 Mon Sep 17 00:00:00 2001 From: Matti Hansson Date: Fri, 25 Feb 2022 12:44:37 +0100 Subject: [PATCH] Make date-time validation align with RFC3339 (#508) --- .../networknt/schema/DateTimeValidator.java | 25 +++++++------------ .../optional/format/date-time.json | 15 +++++++++++ .../resources/draft4/optional/format.json | 12 ++++----- .../draft7/optional/format/date-time.json | 15 +++++++++++ 4 files changed, 45 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/networknt/schema/DateTimeValidator.java b/src/main/java/com/networknt/schema/DateTimeValidator.java index 420aaacda..38f98731d 100644 --- a/src/main/java/com/networknt/schema/DateTimeValidator.java +++ b/src/main/java/com/networknt/schema/DateTimeValidator.java @@ -40,8 +40,8 @@ public class DateTimeValidator extends BaseJsonValidator implements JsonValidato private static final Pattern RFC3339_PATTERN = Pattern.compile( "^(\\d{4})-(\\d{2})-(\\d{2})" // yyyy-MM-dd - + "([Tt](\\d{2}):(\\d{2}):(\\d{2})(\\.\\d+)?)?" // 'T'HH:mm:ss.milliseconds - + "([Zz]|([+-])(\\d{2}):?(\\d{2}))?"); + + "([Tt](\\d{2}):(\\d{2}):(\\d{2})(\\.\\d+)?" // 'T'HH:mm:ss.milliseconds + + "(([Zz])|([+-])(\\d{2}):(\\d{2})))?"); public DateTimeValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext, String formatName) { super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.DATETIME, validationContext); @@ -82,12 +82,12 @@ private boolean isLegalDateTime(String string) { pattern.append("yyyy-MM-dd"); boolean isTimeGiven = matcher.group(4) != null; - String timeZoneShiftRegexGroup = matcher.group(9); - boolean isTimeZoneShiftGiven = timeZoneShiftRegexGroup != null; + boolean isOffsetZuluTime = matcher.group(10) != null; String hour = null; String minute = null; String second = null; String milliseconds = null; + String timeShiftSign = null; String timeShiftHour = null; String timeShiftMinute = null; @@ -96,12 +96,6 @@ private boolean isLegalDateTime(String string) { return false; } - if (!isTimeGiven && isTimeZoneShiftGiven) { - logger.error("Invalid date/time format, cannot specify time zone shift" + - " without specifying time: " + string); - return false; - } - if (isTimeGiven) { hour = matcher.group(5); minute = matcher.group(6); @@ -121,16 +115,15 @@ private boolean isLegalDateTime(String string) { dateTime.append(milliseconds); pattern.append(".SSS"); } - } - if (isTimeGiven && isTimeZoneShiftGiven) { - if (Character.toUpperCase(timeZoneShiftRegexGroup.charAt(0)) == 'Z') { + if (isOffsetZuluTime) { dateTime.append('Z'); pattern.append("'Z'"); } else { - timeShiftHour = matcher.group(11); - timeShiftMinute = matcher.group(12); - dateTime.append(matcher.group(10).charAt(0)).append(timeShiftHour).append(':').append(timeShiftMinute); + timeShiftSign = matcher.group(11); + timeShiftHour = matcher.group(12); + timeShiftMinute = matcher.group(13); + dateTime.append(timeShiftSign).append(timeShiftHour).append(':').append(timeShiftMinute); pattern.append("XXX"); } } diff --git a/src/test/resources/draft2019-09/optional/format/date-time.json b/src/test/resources/draft2019-09/optional/format/date-time.json index b5c89636e..11af9acaf 100644 --- a/src/test/resources/draft2019-09/optional/format/date-time.json +++ b/src/test/resources/draft2019-09/optional/format/date-time.json @@ -49,6 +49,21 @@ "description": "only RFC3339 not all of ISO 8601 are valid", "data": "2013-350T01:01:01", "valid": false + }, + { + "description": "an invalid date-time string without offset", + "data": "1963-06-19T08:30:06", + "valid": false + }, + { + "description": "an invalid date-time string with only hours in offset", + "data": "1963-06-19T08:30:06+02", + "valid": false + }, + { + "description": "an invalid date-time string without colon in offset", + "data": "1963-06-19T08:30:06+0200", + "valid": false } ] } diff --git a/src/test/resources/draft4/optional/format.json b/src/test/resources/draft4/optional/format.json index 4a1328d7d..6b9ab7ded 100644 --- a/src/test/resources/draft4/optional/format.json +++ b/src/test/resources/draft4/optional/format.json @@ -11,9 +11,9 @@ "valid": true }, { - "description": "a valid date-time string without colon", + "description": "an invalid date-time string without colon", "data": "2018-07-27T00:00:01.000-0300", - "valid": true + "valid": false }, { "description": "a valid date-time string", @@ -56,14 +56,14 @@ "valid": true }, { - "description": "an valid date-time string", + "description": "an invalid date-time string", "data": "1963-12-30T08:30:06.283", - "valid": true + "valid": false }, { - "description": "an valid date-time string", + "description": "an invalid date-time string", "data": "1963-12-30T08:30:06", - "valid": true + "valid": false }, { "description": "an valid date-time string", diff --git a/src/test/resources/draft7/optional/format/date-time.json b/src/test/resources/draft7/optional/format/date-time.json index b5c89636e..11af9acaf 100644 --- a/src/test/resources/draft7/optional/format/date-time.json +++ b/src/test/resources/draft7/optional/format/date-time.json @@ -49,6 +49,21 @@ "description": "only RFC3339 not all of ISO 8601 are valid", "data": "2013-350T01:01:01", "valid": false + }, + { + "description": "an invalid date-time string without offset", + "data": "1963-06-19T08:30:06", + "valid": false + }, + { + "description": "an invalid date-time string with only hours in offset", + "data": "1963-06-19T08:30:06+02", + "valid": false + }, + { + "description": "an invalid date-time string without colon in offset", + "data": "1963-06-19T08:30:06+0200", + "valid": false } ] }