Skip to content

Commit 2d02a0f

Browse files
committed
fix: fix iso-date-time validation and add tests for date-time validation in full mode
1 parent e3e7612 commit 2d02a0f

File tree

3 files changed

+137
-11
lines changed

3 files changed

+137
-11
lines changed

src/formats.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ export const fullFormats: DefinedFormats = {
4747
date: fmtDef(date, compareDate),
4848
// date-time: http://tools.ietf.org/html/rfc3339#section-5.6
4949
time: fmtDef(getTime(true), compareTime),
50-
"date-time": fmtDef(getDateTime(true), compareDateTime),
50+
"date-time": fmtDef(getDateTime(), compareDateTime),
5151
"iso-time": fmtDef(getTime(), compareIsoTime),
52-
"iso-date-time": fmtDef(getDateTime(), compareIsoDateTime),
52+
"iso-date-time": fmtDef(getDateTime(true), compareIsoDateTime),
5353
// duration: https://tools.ietf.org/html/rfc3339#appendix-A
5454
duration: /^P(?!$)((\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?|(\d+W)?)$/,
5555
uri,
@@ -110,7 +110,7 @@ export const fastFormats: DefinedFormats = {
110110
compareIsoTime
111111
),
112112
"iso-date-time": fmtDef(
113-
/^\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,
113+
/^\d\d\d\d-((0[1-9])|(1[0-2]))-((0[1-9])|([1-2]\d)|(3[01]))[t\s](?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)?$/i,
114114
compareIsoDateTime
115115
),
116116
// uri: https://github.com/mafintosh/is-my-json-valid/blob/master/formats.js
@@ -198,12 +198,13 @@ function compareIsoTime(t1: string, t2: string): number | undefined {
198198
}
199199

200200
const DATE_TIME_SEPARATOR = /t/i
201-
function getDateTime(strictTimeZone?: boolean): (str: string) => boolean {
202-
const time = getTime(strictTimeZone)
201+
const ISO_DATE_TIME_SEPARATOR = /t|\s/i
202+
function getDateTime(iso?: boolean): (str: string) => boolean {
203+
const time = getTime(!iso)
203204

204205
return function date_time(str: string): boolean {
205206
// http://tools.ietf.org/html/rfc3339#section-5.6
206-
const dateTime: string[] = str.split(DATE_TIME_SEPARATOR)
207+
const dateTime: string[] = str.split(iso ? ISO_DATE_TIME_SEPARATOR : DATE_TIME_SEPARATOR)
207208
return dateTime.length === 2 && date(dateTime[0]) && time(dateTime[1])
208209
}
209210
}
@@ -218,8 +219,8 @@ function compareDateTime(dt1: string, dt2: string): number | undefined {
218219

219220
function compareIsoDateTime(dt1: string, dt2: string): number | undefined {
220221
if (!(dt1 && dt2)) return undefined
221-
const [d1, t1] = dt1.split(DATE_TIME_SEPARATOR)
222-
const [d2, t2] = dt2.split(DATE_TIME_SEPARATOR)
222+
const [d1, t1] = dt1.split(ISO_DATE_TIME_SEPARATOR)
223+
const [d2, t2] = dt2.split(ISO_DATE_TIME_SEPARATOR)
223224
const res = compareDate(d1, d2)
224225
if (res === undefined) return undefined
225226
return res || compareTime(t1, t2)

tests/extras/format.json

Lines changed: 123 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,7 @@
560560
]
561561
},
562562
{
563-
"description": "validation of date-time strings",
563+
"description": "validation of iso-date-time strings",
564564
"schema": {"format": "iso-date-time"},
565565
"tests": [
566566
{
@@ -599,8 +599,129 @@
599599
"valid": true
600600
},
601601
{
602-
"description": "an invalid iso-date-time string (space separator)",
602+
"description": "a valid iso-date-time string (space separator)",
603603
"data": "2016-12-31 23:59:60Z",
604+
"valid": true
605+
}
606+
]
607+
},
608+
{
609+
"description": "validation of date-time strings",
610+
"schema": {"format": "date-time"},
611+
"tests": [
612+
{
613+
"description": "a valid date-time string",
614+
"data": "2016-12-31T23:59:60Z",
615+
"valid": true
616+
},
617+
{
618+
"description": "a valid date-time string",
619+
"data": "2015-12-31t23:59:60Z",
620+
"valid": true
621+
},
622+
{
623+
"description": "a valid date-time string",
624+
"data": "2015-02-11t22:59:22Z",
625+
"valid": true
626+
},
627+
{
628+
"description": "a valid date-time string",
629+
"data": "2020-01-01T20:00:00.000Z",
630+
"valid": true
631+
},
632+
{
633+
"description": "a valid date-time string",
634+
"data": "2020-01-01T20:00:00.000Z",
635+
"valid": true
636+
},
637+
{
638+
"description": "a valid date-time string",
639+
"data": "2023-05-04T01:14:00+21:00",
640+
"valid": true
641+
},
642+
{
643+
"description": "a valid date-time string",
644+
"data": "2023-05-04T01:14:10+16:20",
645+
"valid": true
646+
},
647+
{
648+
"description": "a valid date-time string",
649+
"data": "2023-05-04T01:14:21+09:50",
650+
"valid": true
651+
},
652+
{
653+
"description": "a valid date-time string",
654+
"data": "2023-05-04T01:14:21-04:31",
655+
"valid": true
656+
},
657+
{
658+
"description": "a valid date-time string",
659+
"data": "2023-05-04T01:14:21-23:59",
660+
"valid": true
661+
},
662+
{
663+
"description": "an invalid date-time string (invalid month)",
664+
"data": "2016-15-31T23:59:60Z",
665+
"valid": false
666+
},
667+
{
668+
"description": "an invalid date-time string (invalid month)",
669+
"data": "2015-00-11t22:59:22+00:00",
670+
"valid": false
671+
},
672+
{
673+
"description": "an invalid date-time string (invalid day)",
674+
"data": "2015-01-00T22:59:22+00:00",
675+
"valid": false
676+
},
677+
{
678+
"description": "an invalid date-time string (invalid separator)",
679+
"data": "2016-12-31 23:59:60Z",
680+
"valid": false
681+
},
682+
{
683+
"description": "an invalid date-time string (invalid time)",
684+
"data": "2015-02-11t24:59:22Z",
685+
"valid": false
686+
},
687+
{
688+
"description": "an invalid date-time string (invalid separator and time-offset)",
689+
"data": "2020-01-01 20:00:00.000",
690+
"valid": false
691+
},
692+
{
693+
"description": "an invalid date-time string (invalid separator)",
694+
"data": "2020-01-01 20:00:00.000Z",
695+
"valid": false
696+
},
697+
{
698+
"description": "an invalid date-time string (invalid separator)",
699+
"data": "2023-05-04\t01:14:00+21:00",
700+
"valid": false
701+
},
702+
{
703+
"description": "an invalid date-time string (invalid separator)",
704+
"data": "2023-05-04\r01:14:10+16:20",
705+
"valid": false
706+
},
707+
{
708+
"description": "an invalid date-time string (invalid timezone)",
709+
"data": "2015-02-11t22:59:22+24:30",
710+
"valid": false
711+
},
712+
{
713+
"description": "an invalid date-time string (invalid separator)",
714+
"data": "2023-05-04\n01:14:21+09:50",
715+
"valid": false
716+
},
717+
{
718+
"description": "an invalid date-time string (invalid separator)",
719+
"data": "2023-05-04\n01:14:21-04:31",
720+
"valid": false
721+
},
722+
{
723+
"description": "",
724+
"data": "2023-05-04t01:14:21-04:31:00 (invalid time-offset)",
604725
"valid": false
605726
}
606727
]

tests/index.spec.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ describe("addFormats options", () => {
2525
})
2626

2727
test("should support validation mode", () => {
28-
addFormats(ajv, {mode: "fast", formats: ["date", "time", "date-time"]})
28+
addFormats(ajv, {mode: "fast", formats: ["date", "time", "date-time", "iso-date-time"]})
2929
const validateDate = ajv.compile({format: "date"})
3030
expect(validateDate("2020-09-17")).toEqual(true)
3131
expect(validateDate("2020-09-35")).toEqual(true)
@@ -60,6 +60,10 @@ describe("addFormats options", () => {
6060
expect(validateDatetime("2023-05-04\n01:14:21+09:50")).toEqual(false)
6161
expect(validateDatetime("2023-05-04\n01:14:21-04:31")).toEqual(false)
6262
expect(validateDatetime("2023-05-04t01:14:21-04:31:00")).toEqual(false)
63+
64+
const validateIsoDatetime = ajv.compile({format: "iso-date-time"})
65+
expect(validateIsoDatetime("2016-12-31 23:59:60Z")).toEqual(true)
66+
expect(validateIsoDatetime("2016-13-31 23:59:60Z")).toEqual(false)
6367
})
6468
})
6569

0 commit comments

Comments
 (0)