Posted at

Swift4のJSONDecorderは、Date等のパース方法をカスタマイズできるみたい

More than 1 year has passed since last update.

とりあえずサンプルコード

import Foundation

struct S1: Codable {
let dateFromTimeInterval: Date
}

struct S2: Codable {
let dateFromISO8601: Date
}

struct S3: Codable {
let dateFromCustomFormat: Date
}

let data = """
{
"
dateFromTimeInterval": 540000000,
"
dateFromISO8601": "2017-01-01T12:34:56Z",
"
dateFromCustomFormat": "2034ねん03がつ04にち05じ06ふん07びょう",
}
"""
.data(using: .utf8)!

do {
do {
let decoder = JSONDecoder()
let t = try decoder.decode(S1.self, from: data)
print(t)
}
do {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let t = try decoder.decode(S2.self, from: data)
print(t)
}
do {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted({
let f = DateFormatter()
f.calendar = Calendar(identifier: .gregorian)
f.locale = .current
f.dateFormat = "yyyyねんMMがつddにちHHじmmふんssびょう"
return f
}())

let t = try decoder.decode(S3.self, from: data)
print(t)
}
do {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .custom {
let container = try $0.singleValueContainer()
let str = try container.decode(String.self)
let f = DateFormatter()
f.calendar = Calendar(identifier: .gregorian)
f.locale = .current
f.dateFormat = "yyyyねんMMがつddにちHHじmmふんssびょう"
return f.date(from: str)!
}
let t = try decoder.decode(S3.self, from: data)
print(t)
}
} catch {
print(error)
}

/* 結果
S1(dateFromTimeInterval: 2018-02-11 00:00:00 +0000)
S2(dateFromISO8601: 2017-01-01 12:34:56 +0000)
S3(dateFromCustomFormat: 2034-03-04 13:06:07 +0000)
S3(dateFromCustomFormat: 2034-03-04 13:06:07 +0000)
*/

Date以外も、Strategyとして設定できるものはいくつかあるみたい

    /// The strategy to use for decoding `Date` values.

public enum DateDecodingStrategy {

/// Defer to `Date` for decoding. This is the default strategy.
case deferredToDate

/// Decode the `Date` as a UNIX timestamp from a JSON number.
case secondsSince1970

/// Decode the `Date` as UNIX millisecond timestamp from a JSON number.
case millisecondsSince1970

/// Decode the `Date` as an ISO-8601-formatted string (in RFC 3339 format).
case iso8601

/// Decode the `Date` as a string parsed by the given formatter.
case formatted(DateFormatter)

/// Decode the `Date` as a custom value decoded by the given closure.
case custom((Decoder) throws -> Date)
}

/// The strategy to use for decoding `Data` values.
public enum DataDecodingStrategy {

/// Decode the `Data` from a Base64-encoded string. This is the default strategy.
case base64Decode

/// Decode the `Data` as a custom value decoded by the given closure.
case custom((Decoder) throws -> Data)
}

/// The strategy to use for non-JSON-conforming floating-point values (IEEE 754 infinity and NaN).
public enum NonConformingFloatDecodingStrategy {

/// Throw upon encountering non-conforming values. This is the default strategy.
case `throw`

/// Decode the values from the given representation strings.
case convertFromString(positiveInfinity: String, negativeInfinity: String, nan: String)
}

/// The strategy to use in decoding dates. Defaults to `.deferredToDate`.
open var dateDecodingStrategy: JSONDecoder.DateDecodingStrategy

/// The strategy to use in decoding binary data. Defaults to `.base64Decode`.
open var dataDecodingStrategy: JSONDecoder.DataDecodingStrategy

/// The strategy to use in decoding non-conforming numbers. Defaults to `.throw`.
open var nonConformingFloatDecodingStrategy: JSONDecoder.NonConformingFloatDecodingStrategy

ちなみに、JSONDecoder だけでなく JSONEncoder 側にもカスタマイズ可能なプロパティがいくつかあるので覚えておくとよさそう


参考リンク

JSONDecoder - Foundation | Apple Developer Documentation

JSONEncoder - Foundation | Apple Developer Documentation