Skip to content

Commit 12bbf6d

Browse files
committed
wip: time format
1 parent 931e87e commit 12bbf6d

File tree

5 files changed

+76
-3
lines changed

5 files changed

+76
-3
lines changed

Sources/Draft201909Validator.swift

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ public class Draft201909Validator: Validator {
6262
"regex": validateRegex,
6363
"json-pointer": validateJSONPointer,
6464
"duration": validateDuration,
65+
"time": validateTime,
6566
]
6667

6768
public required init(schema: Bool) {

Sources/Draft202012Validator.swift

+1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ public class Draft202012Validator: Validator {
6363
"regex": validateRegex,
6464
"json-pointer": validateJSONPointer,
6565
"duration": validateDuration,
66+
"time": validateTime,
6667
]
6768

6869
public required init(schema: Bool) {

Sources/Draft7Validator.swift

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public class Draft7Validator: Validator {
5050
"uri": validateURI,
5151
"json-pointer": validateJSONPointer,
5252
"regex": validateRegex,
53+
"time": validateTime,
5354
]
5455

5556
public required init(schema: Bool) {

Sources/Format/time.swift

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import Foundation
2+
3+
4+
/*
5+
partial-time https://tools.ietf.org/html/rfc3339
6+
7+
time-hour = 2DIGIT ; 00-23
8+
time-minute = 2DIGIT ; 00-59
9+
time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second
10+
; rules
11+
time-secfrac = "." 1*DIGIT
12+
time-numoffset = ("+" / "-") time-hour ":" time-minute
13+
time-offset = "Z" / time-numoffset
14+
15+
partial-time = time-hour ":" time-minute ":" time-second
16+
[time-secfrac]
17+
*/
18+
19+
20+
var timeExpression: NSRegularExpression = {
21+
let time = #"""
22+
(?x)
23+
^
24+
(?<hour>(([01]\d)|(2[0-3])))
25+
:
26+
(?<minute>([0-5]\d))
27+
:
28+
(?<second>(([0-5]\d)|(60)))
29+
(?<secfrac>\.\d+)?
30+
(?<offset>
31+
(
32+
Z
33+
|
34+
(?<numoffset>[+-]
35+
(([01]\d)|2[0-3])
36+
:
37+
([0-5]\d)
38+
)
39+
)
40+
)
41+
$
42+
"""#
43+
return try! NSRegularExpression(pattern: time, options: [.caseInsensitive])
44+
}()
45+
46+
47+
func isValidTime(_ value: String) -> Bool {
48+
guard let match = timeExpression.firstMatch(in: value, range: NSMakeRange(0, value.utf16.count)) else {
49+
return false
50+
}
51+
52+
// FIXME if seconds is 60
53+
// Z offset: only pass if hour=23 && minute=59
54+
// if -00:00 offset, pass
55+
// deduct or add offset to hour/minute and verify hour=23 && minute=59
56+
57+
return true
58+
}
59+
60+
61+
func validateTime(_ context: Context, _ value: String) -> AnySequence<ValidationError> {
62+
if isValidTime(value) {
63+
return AnySequence(EmptyCollection())
64+
}
65+
66+
return AnySequence([
67+
ValidationError(
68+
"'\(value)' is not a valid RFC 3339 formatted time.",
69+
instanceLocation: context.instanceLocation,
70+
keywordLocation: context.keywordLocation
71+
)
72+
])
73+
}

Tests/JSONSchemaTests/JSONSchemaCases.swift

-3
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,6 @@ class JSONSchemaCases: XCTestCase {
146146
"iri-reference.json",
147147
"iri.json",
148148
"relative-json-pointer.json",
149-
"time.json",
150149
"uri-reference.json",
151150
"uri-template.json",
152151
] + additionalExclusions)
@@ -182,7 +181,6 @@ class JSONSchemaCases: XCTestCase {
182181
"iri-reference.json",
183182
"iri.json",
184183
"relative-json-pointer.json",
185-
"time.json",
186184
"uri-reference.json",
187185
"uri-template.json",
188186
] + additionalExclusions)
@@ -217,7 +215,6 @@ class JSONSchemaCases: XCTestCase {
217215
"iri-reference.json",
218216
"iri.json",
219217
"relative-json-pointer.json",
220-
"time.json",
221218
"uri-reference.json",
222219
"uri-template.json",
223220
] + additionalExclusions)

0 commit comments

Comments
 (0)