Skip to content

Commit 335d0ea

Browse files
authored
Test case and example for using date with a propertyWrapper. (#17)
1 parent 29fc2d7 commit 335d0ea

File tree

2 files changed

+124
-2
lines changed

2 files changed

+124
-2
lines changed

README.md

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Add `pure-swift-json` as dependency to your `Package.swift`:
3535

3636
```swift
3737
dependencies: [
38-
.package(url: "https://github.com/fabianfett/pure-swift-json.git", .upToNextMajore(from: "0.1.0")),
38+
.package(url: "https://github.com/fabianfett/pure-swift-json.git", .upToNextMajor(from: "0.1.0")),
3939
],
4040
```
4141

@@ -125,7 +125,7 @@ struct MyEvent: Decodable {
125125
guard let timestamp = MyEvent.dateFormatter.date(from: dateString) else {
126126
let dateFormat = String(describing: MyEvent.dateFormatter.dateFormat)
127127
throw DecodingError.dataCorruptedError(forKey: .eventTime, in: container, debugDescription:
128-
"Expected date to be in format `\(dateFormat)`, but `\(dateFormat) does not forfill format`")
128+
"Expected date to be in format `\(dateFormat)`, but `\(dateString) does not forfill format`")
129129
}
130130
self.eventTime = timestamp
131131
}
@@ -143,6 +143,48 @@ struct MyEvent: Decodable {
143143

144144
You can find more information about [encoding and decoding custom types in Apple's documentation](https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types).
145145

146+
Of course you can use `@propertyWrapper`s to make this more elegant:
147+
148+
```swift
149+
import Foundation
150+
151+
@propertyWrapper
152+
struct DateStringCoding: Decodable {
153+
var wrappedValue: Date
154+
155+
init(wrappedValue: Date) {
156+
self.wrappedValue = wrappedValue
157+
}
158+
159+
init(from decoder: Decoder) throws {
160+
let container = try decoder.singleValueContainer()
161+
let dateString = try container.decode(String.self)
162+
guard let date = Self.dateFormatter.date(from: dateString) else {
163+
let dateFormat = String(describing: Self.dateFormatter.dateFormat)
164+
throw DecodingError.dataCorruptedError(in: container, debugDescription:
165+
"Expected date to be in format `\(dateFormat)`, but `\(dateString) does not forfill format`")
166+
}
167+
self.wrappedValue = date
168+
}
169+
170+
private static let dateFormatter: DateFormatter = Self.createDateFormatter()
171+
private static func createDateFormatter() -> DateFormatter {
172+
let formatter = DateFormatter()
173+
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
174+
formatter.timeZone = TimeZone(secondsFromGMT: 0)
175+
formatter.locale = Locale(identifier: "en_US_POSIX")
176+
return formatter
177+
}
178+
}
179+
180+
struct MyEvent: Decodable {
181+
@DateStringCoding
182+
var eventTime: Date
183+
}
184+
```
185+
186+
Checkout the a full example in the test file [DateCodingTests](https://github.com/fabianfett/pure-swift-json/blob/master/Tests/JSONCodingTests/DateCodingTests.swift).
187+
146188
### UTF-16 and UTF-32
147189

148190
If your input is [UTF-16](https://en.wikipedia.org/wiki/UTF-16) or [UTF-32](https://en.wikipedia.org/wiki/UTF-32) encoded, you can easily convert it to UTF-8:
@@ -173,3 +215,4 @@ Focus areas for the time being:
173215
- [@weissi](https://github.com/weissi) thanks for answering all my questions and for opening tickets [SR-12125](https://bugs.swift.org/browse/SR-12125) and [SR-12126](https://bugs.swift.org/browse/SR-12126)
174216
- [@dinhhungle](https://github.com/dinhhungle) thanks for your quality assurance. It helped a lot!
175217
- [@Ro-M](https://github.com/Ro-M) thanks for checking my README.md
218+
- [@Trzyipolkostkicukru](https://github.com/Trzyipolkostkicukru) thanks for your advice on `@propertyWrappers` and for finding typos.
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import XCTest
2+
@testable import PureSwiftJSONCoding
3+
4+
class DateCodingTests: XCTestCase {
5+
6+
@propertyWrapper
7+
struct DateStringCoding: Codable {
8+
var wrappedValue: Date
9+
10+
init(wrappedValue: Date) {
11+
self.wrappedValue = wrappedValue
12+
}
13+
14+
init(from decoder: Decoder) throws {
15+
let container = try decoder.singleValueContainer()
16+
let dateString = try container.decode(String.self)
17+
guard let date = Self.dateFormatter.date(from: dateString) else {
18+
let dateFormat = String(describing: Self.dateFormatter.dateFormat)
19+
throw DecodingError.dataCorruptedError(in: container, debugDescription:
20+
"Expected date to be in format `\(dateFormat)`, but `\(dateString) does not forfill format`")
21+
}
22+
self.wrappedValue = date
23+
}
24+
25+
func encode(to encoder: Encoder) throws {
26+
var container = encoder.singleValueContainer()
27+
let dateString = Self.dateFormatter.string(from: self.wrappedValue)
28+
try container.encode(dateString)
29+
}
30+
31+
private static let dateFormatter: DateFormatter = Self.createDateFormatter()
32+
private static func createDateFormatter() -> DateFormatter {
33+
let formatter = DateFormatter()
34+
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
35+
formatter.timeZone = TimeZone(secondsFromGMT: 0)
36+
formatter.locale = Locale(identifier: "en_US_POSIX")
37+
return formatter
38+
}
39+
}
40+
41+
struct MyEvent: Codable {
42+
@DateStringCoding
43+
var eventTime: Date
44+
}
45+
46+
func testDecodeDatePropertyWrapper() {
47+
do {
48+
let dateString = "2020-03-18T13:11:10.000Z"
49+
let json = #"{"eventTime": "\#(dateString)"}"#
50+
let result = try PureSwiftJSONCoding.JSONDecoder().decode(MyEvent.self, from: [UInt8](json.utf8))
51+
52+
let components = DateComponents(
53+
calendar: Calendar(identifier: .gregorian), timeZone: TimeZone(secondsFromGMT: 0),
54+
year: 2020, month: 03, day: 18, hour: 13, minute: 11, second: 10, nanosecond: 0)
55+
XCTAssertEqual(result.eventTime, components.date)
56+
}
57+
catch {
58+
XCTFail("Unexpected error: \(error)")
59+
}
60+
}
61+
62+
func testEncodeDatePropertyWrapper() {
63+
do {
64+
let dateString = "2020-03-18T13:11:10.000Z"
65+
let json = #"{"eventTime":"\#(dateString)"}"#
66+
67+
let components = DateComponents(
68+
calendar: Calendar(identifier: .gregorian), timeZone: TimeZone(secondsFromGMT: 0),
69+
year: 2020, month: 03, day: 18, hour: 13, minute: 11, second: 10, nanosecond: 0)
70+
71+
let event = MyEvent(eventTime: components.date!)
72+
let bytes = try PureSwiftJSONCoding.JSONEncoder().encode(event)
73+
XCTAssertEqual(String(decoding: bytes, as: Unicode.UTF8.self), json)
74+
}
75+
catch {
76+
XCTFail("Unexpected error: \(error)")
77+
}
78+
}
79+
}

0 commit comments

Comments
 (0)