APIから日付をDecodeする(Encode)
TwitterなどのAPIから日付を取得(Decode)する際に、日付が文字列形式のことがあります。
その時のDecode/ Encodeの実装時には注意が必要です。
Date(日付)は情報量が多く、人間が簡単に見やすい形式yyyy-MM-dd'T'HH:mm:ssZZZZZ
に変換してJSONにする(Encode/Decode)のでは、情報量が落ちてしまいます。
情報量が落ちてしまう例
このJSONを生成するには、JSONEncoderのdateEncodingStrategyを設定する必要があります。
{
"name":"zunda",
"createdAt":"2022-12-02T10:12:19Z"
}
struct User: Codable, Equatable {
let name: String
let createdAt: Date
}
let user = User(name: "zunda", createdAt: Date())
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
let data = try encoder.encode(user)
print(String(data: data, encoding: .utf8)!)
生成したJSONをDecodeして同じ日付であるかをチェックする
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let decodedUser = try decoder.decode(User.self, from: data)
// 比較
let sameDate = user.createdAt == decodedUser.createdAt // falseになる
// ここで情報量が落ちていることが確認できる
print(user.createdAt.timeIntervalSinceReferenceDate) // 691669442.562633
print(decodedUser.createdAt.timeIntervalSinceReferenceDate) // 691669442.0
情報量を落とさない方法
標準の方法では実は情報量は落とさず、Encode/Decodeすることができます。
しかし人間が見ても簡単には、日付がわかりません。
標準方法でEncodeすると以下のような形になります。これはDecodeしても情報量が落ちません。
{
"name":"zunda",
"createdAt":691668705.64202905
}
let user = User(name: "zunda", createdAt: Date())
let encoder = JSONEncoder()
let data = try encoder.encode(user)
print(String(data: data, encoding: .utf8)!)
let decoder = JSONDecoder()
let decodedUser = try decoder.decode(User.self, from: data)
print(user.createdAt.timeIntervalSinceReferenceDate)
print(decodedUser.createdAt.timeIntervalSinceReferenceDate)
Encode/ Decodeのテストができない
作成したモデルをEncodeして、Decodeすることで、EncodeとDecodeの整合性をテストするといったことが文字列日付を使用しようとするとできないです。
テスト時はdateDecodingStrategy, dateEncodingStrategyを設定しない
などで対処するしかないかもしれません。