diff --git a/src/formats.ts b/src/formats.ts index b1babd6..d3cde9b 100644 --- a/src/formats.ts +++ b/src/formats.ts @@ -48,8 +48,8 @@ export const fullFormats: DefinedFormats = { // date-time: http://tools.ietf.org/html/rfc3339#section-5.6 time: fmtDef(getTime(true), compareTime), "date-time": fmtDef(getDateTime(true), compareDateTime), - "iso-time": fmtDef(getTime(), compareTime), - "iso-date-time": fmtDef(getDateTime(), compareDateTime), + "iso-time": fmtDef(getTime(), compareIsoTime), + "iso-date-time": fmtDef(getDateTime(), compareIsoDateTime), // duration: https://tools.ietf.org/html/rfc3339#appendix-A duration: /^P(?!$)((\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?|(\d+W)?)$/, uri, @@ -107,11 +107,11 @@ export const fastFormats: DefinedFormats = { ), "iso-time": fmtDef( /^(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)?$/i, - compareTime + compareIsoTime ), "iso-date-time": fmtDef( /^\d\d\d\d-[0-1]\d-[0-3]\d[t\s](?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)?$/i, - compareDateTime + compareIsoDateTime ), // uri: https://github.com/mafintosh/is-my-json-valid/blob/master/formats.js uri: /^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/)?[^\s]*$/i, @@ -177,7 +177,15 @@ function getTime(strictTimeZone?: boolean): (str: string) => boolean { } } -function compareTime(t1: string, t2: string): number | undefined { +function compareTime(s1: string, s2: string): number | undefined { + if (!(s1 && s2)) return undefined + const t1 = new Date("2020-01-01T" + s1).valueOf() + const t2 = new Date("2020-01-01T" + s2).valueOf() + if (!(t1 && t2)) return undefined + return t1 - t2 +} + +function compareIsoTime(t1: string, t2: string): number | undefined { if (!(t1 && t2)) return undefined const a1 = TIME.exec(t1) const a2 = TIME.exec(t2) @@ -201,6 +209,14 @@ function getDateTime(strictTimeZone?: boolean): (str: string) => boolean { } function compareDateTime(dt1: string, dt2: string): number | undefined { + if (!(dt1 && dt2)) return undefined + const d1 = new Date(dt1).valueOf() + const d2 = new Date(dt2).valueOf() + if (!(d1 && d2)) return undefined + return d1 - d2 +} + +function compareIsoDateTime(dt1: string, dt2: string): number | undefined { if (!(dt1 && dt2)) return undefined const [d1, t1] = dt1.split(DATE_TIME_SEPARATOR) const [d2, t2] = dt2.split(DATE_TIME_SEPARATOR) diff --git a/tests/extras/formatMaximum.json b/tests/extras/formatMaximum.json index bca7ab2..f452362 100644 --- a/tests/extras/formatMaximum.json +++ b/tests/extras/formatMaximum.json @@ -49,7 +49,6 @@ } ] }, - { "description": "formatMaximum validation with time format", "schema": { @@ -69,10 +68,20 @@ "valid": true }, { - "description": "boundary point is valid, timezone is ignored", + "description": "time before the maximum time is valid, timezone is taken into account", "data": "13:15:17.000+01:00", "valid": true }, + { + "description": "boundary point is valid, timezone is taken into account", + "data": "14:15:17.000+01:00", + "valid": true + }, + { + "description": "time after the maximum time is invalid, timezone is taken into account", + "data": "14:20:17.000+01:00", + "valid": false + }, { "description": "time before the maximum time is valid", "data": "10:33:55.000Z", @@ -99,13 +108,8 @@ "valid": false }, { - "description": "boundary point is invalid, timezone is ignored", - "data": "13:15:17.000+01:00", - "valid": false - }, - { - "description": "boundary point is invalid, no timezone is ok too", - "data": "13:15:17.000", + "description": "boundary point is invalid, timezone is taken into account", + "data": "14:15:17.000+01:00", "valid": false }, { @@ -115,7 +119,6 @@ } ] }, - { "description": "formatMaximum validation with date-time format", "schema": { @@ -186,6 +189,146 @@ } ] }, + { + "description": "formatMaximum validation with iso-time format", + "schema": { + "type": "string", + "format": "iso-time", + "formatMaximum": "13:15:17.000Z" + }, + "tests": [ + { + "description": "time after the maximum time is invalid", + "data": "15:11:09.000Z", + "valid": false + }, + { + "description": "boundary point is valid", + "data": "13:15:17.000Z", + "valid": true + }, + { + "description": "time before the maximum time is valid, timezone is ignored", + "data": "13:15:16.000+01:00", + "valid": true + }, + { + "description": "boundary point is valid, timezone is ignored", + "data": "13:15:17.000+01:00", + "valid": true + }, + { + "description": "time after the maximum time is invalid, timezone is ignored", + "data": "13:15:18.000+01:00", + "valid": false + }, + { + "description": "time before the maximum time is valid", + "data": "10:33:55.000Z", + "valid": true + } + ] + }, + { + "description": "formatExclusiveMaximum validation with iso-time format", + "schema": { + "type": "string", + "format": "iso-time", + "formatExclusiveMaximum": "13:15:17.000Z" + }, + "tests": [ + { + "description": "time after the maximum time is still invalid", + "data": "15:11:09.000Z", + "valid": false + }, + { + "description": "boundary point is invalid", + "data": "13:15:17.000Z", + "valid": false + }, + { + "description": "boundary point is invalid, timezone is ignored", + "data": "13:15:17.000+01:00", + "valid": false + }, + { + "description": "time before the maximum time is still valid", + "data": "10:33:55.000Z", + "valid": true + } + ] + }, + { + "description": "formatMaximum validation with iso-date-time format", + "schema": { + "type": "string", + "format": "iso-date-time", + "formatMaximum": "2015-08-17T13:15:17.000Z" + }, + "tests": [ + { + "description": "date after the maximum date is invalid", + "data": "2015-11-09T13:15:17.000Z", + "valid": false + }, + { + "description": "same date, time after the maximum time is invalid", + "data": "2015-08-17T15:11:09.000Z", + "valid": false + }, + { + "description": "boundary point is valid", + "data": "2015-08-17T13:15:17.000Z", + "valid": true + }, + { + "description": "same date, time before the maximum time is valid", + "data": "2015-08-17T10:33:55.000Z", + "valid": true + }, + { + "description": "date before the maximum date is valid", + "data": "2014-12-03T13:15:17.000Z", + "valid": true + } + ] + }, + { + "description": "formatExclusiveMaximum validation with iso-date-time format", + "schema": { + "type": "string", + "format": "iso-date-time", + "formatExclusiveMaximum": "2015-08-17T13:15:17.000Z" + }, + "tests": [ + { + "description": "date after the maximum date is still invalid", + "data": "2015-11-09T13:15:17.000Z", + "valid": false + }, + { + "description": "same date, time after the maximum time is still invalid", + "data": "2015-08-17T15:11:09.000Z", + "valid": false + }, + { + "description": "boundary point is invalid", + "data": "2015-08-17T13:15:17.000Z", + "valid": false + }, + { + "description": "same date, time before the maximum time is still valid", + "data": "2015-08-17T10:33:55.000Z", + "valid": true + }, + { + "description": "date before the maximum date is still valid", + "data": "2014-12-03T13:15:17.000Z", + "valid": true + } + ] + }, { "description": "formatMaximum is valid with whitelisted unknown format", "schema": { diff --git a/tests/extras/formatMinimum.json b/tests/extras/formatMinimum.json index e6fb7d3..7d8e1d7 100644 --- a/tests/extras/formatMinimum.json +++ b/tests/extras/formatMinimum.json @@ -49,7 +49,6 @@ } ] }, - { "description": "formatMinimum validation with time format", "schema": { @@ -69,8 +68,18 @@ "valid": true }, { - "description": "boundary point is valid, timezone is ignored", + "description": "time before the minimum time is invalid, timezone is taken into account", "data": "13:15:17.000+01:00", + "valid": false + }, + { + "description": "boundary point is valid, timezone is taken into account", + "data": "14:15:17.000+01:00", + "valid": true + }, + { + "description": "time after the minimum time is valid, timezone is taken into account", + "data": "14:20:17.000+01:00", "valid": true }, { @@ -99,8 +108,8 @@ "valid": false }, { - "description": "boundary point is invalid, timezone is ignored", - "data": "13:15:17.000+01:00", + "description": "boundary point is invalid, timezone is taken into account", + "data": "14:15:17.000+01:00", "valid": false }, { @@ -184,5 +193,150 @@ "valid": false } ] + }, + { + "description": "formatMinimum validation with iso-time format", + "schema": { + "type": "string", + "format": "iso-time", + "formatMinimum": "13:15:17.000Z" + }, + "tests": [ + { + "description": "time after the minimum time is valid", + "data": "15:11:09.000Z", + "valid": true + }, + { + "description": "boundary point is valid", + "data": "13:15:17.000Z", + "valid": true + }, + { + "description": "time before the minimum time is invalid, timezone is ignored", + "data": "13:15:16.000+01:00", + "valid": false + }, + { + "description": "boundary point is valid, timezone is ignored", + "data": "13:15:17.000+01:00", + "valid": true + }, + { + "description": "time after the minimum time is valid, timezone is ignored", + "data": "13:15:18.000+01:00", + "valid": true + }, + { + "description": "time before the minimum time is invalid", + "data": "10:33:55.000Z", + "valid": false + } + ] + }, + { + "description": "formatExclusiveMinimum validation with iso-time format", + "schema": { + "type": "string", + "format": "iso-time", + "formatExclusiveMinimum": "13:15:17.000Z" + }, + "tests": [ + { + "description": "time after the minimum time is still valid", + "data": "15:11:09.000Z", + "valid": true + }, + { + "description": "boundary point is invalid", + "data": "13:15:17.000Z", + "valid": false + }, + { + "description": "boundary point is invalid, timezone is ignored", + "data": "13:15:17.000+01:00", + "valid": false + }, + { + "description": "boundary point is invalid, no timezone is ok too", + "data": "13:15:17.000", + "valid": false + }, + { + "description": "time before the minimum time is still invalid", + "data": "10:33:55.000Z", + "valid": false + } + ] + }, + { + "description": "formatMinimum validation with iso-date-time format", + "schema": { + "type": "string", + "format": "iso-date-time", + "formatMinimum": "2015-08-17T13:15:17.000Z" + }, + "tests": [ + { + "description": "date after the minimum date is valid", + "data": "2015-11-09T13:15:17.000Z", + "valid": true + }, + { + "description": "same date, time after the minimum time is valid", + "data": "2015-08-17T15:11:09.000Z", + "valid": true + }, + { + "description": "boundary point is valid", + "data": "2015-08-17T13:15:17.000Z", + "valid": true + }, + { + "description": "same date, time before the minimum time is invalid", + "data": "2015-08-17T10:33:55.000Z", + "valid": false + }, + { + "description": "date before the minimum date is invalid", + "data": "2014-12-03T13:15:17.000Z", + "valid": false + } + ] + }, + { + "description": "formatExclusiveMinimum validation with iso-date-time format", + "schema": { + "type": "string", + "format": "iso-date-time", + "formatExclusiveMinimum": "2015-08-17T13:15:17.000Z" + }, + "tests": [ + { + "description": "date after the minimum date is still valid", + "data": "2015-11-09T13:15:17.000Z", + "valid": true + }, + { + "description": "same date, time after the minimum time is still valid", + "data": "2015-08-17T15:11:09.000Z", + "valid": true + }, + { + "description": "boundary point is invalid", + "data": "2015-08-17T13:15:17.000Z", + "valid": false + }, + { + "description": "same date, time before the minimum time is still invalid", + "data": "2015-08-17T10:33:55.000Z", + "valid": false + }, + { + "description": "date before the minimum date is still invalid", + "data": "2014-12-03T13:15:17.000Z", + "valid": false + } + ] } ]