是否可以在Firestore时间戳/日期中使用“可解码”?

时间:2018-11-28 00:43:23

标签: ios swift firebase google-cloud-firestore

我有一个[String: Bookmark]字典,但createdAt被保存为Timestamp,在尝试理解Date

时,解码器抛出错误。
  

***由于未捕获的异常'NSInvalidArgumentException'而终止应用程序,原因:'JSON写入(__NSDate)中的类型无效'

struct Bookmark: Decodable {
    let messageId: String
    let messageCreatedAt: Date
}


JSONDecoder().decode([String: Bookmark].self, data: data)

是否有一种方法可以使Swift的Decodable协议与Firestore时间戳完美配合?

编辑:

如果我打印[String: Any],然后尝试像这样在控制台中解码

 ▿ 1 : 2 elements
    - key : "messageCreatedAt"
    - value : 2018-11-27 20:59:11 +0000

po valueDict["messageCreatedAt"] as? Date

我明白了

▿ Optional<Date>
  ▿ some : 2018-11-27 20:59:11 +0000
    - timeIntervalSinceReferenceDate : 565045151.531769

因此必须在Decodable中存在某些内容,才能识别和解析该内容吗?

编辑:

JSON是

{
  "messageId": "abc123",
  "messageCreatedAt": "2018-11-27 20:59:11 +0000"
}

1 个答案:

答案 0 :(得分:1)

JSONDecoder的解码日期如何由.dateDecodingStrategy属性的值定义。

如果您必须从字符串中解析Date,则应使用.iso8601.formatted(_:)(或者,如果您的日期格式确实是自定义的,复杂的和/或很奇怪的,则可能需要使用.custom(_:))。

您的日期字符串几乎是ISO 8601格式的(日期和时间部分之间仅缺少T),但这足以失败。

因此,您最好的选择是使用formatted(_:)

// Declare it somewhere and reuse single instance as much as possible, formatter initialization is quite expensive
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX") // Better to fix Locale here
dateFormatter.dateFormat = "yyyy-MM-dd kk:mm:ss Z"

然后

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(dateFormatter)
let bookmark = try decoder.decode(Bookmark.self, from: data) 

print(bookmark.messageCreatedAt, bookmark.messageCreatedAt.timeIntervalSince1970)
// prints "2018-11-27 20:59:11 +0000 1543352351.0"