如何快速解码来自 Firebase Firestore 的时间戳
Posted
技术标签:
【中文标题】如何快速解码来自 Firebase Firestore 的时间戳【英文标题】:How to decode a TimeStamp from the firebase Firestore in swift 【发布时间】:2019-09-16 01:54:43 【问题描述】:我想通过解析来自 firestore 数据库的响应来解码 TimeStamp(由 FirebaseFirestore.Timestamp 快速定义)。
以下从服务器解析的代码让编译器告诉我:
实例方法 'decode(_:forKey:)' 要求 'Timestamp' 符合 到“可解码”
created = try container.decode(FirebaseFirestore.Timestamp.self, forKey: .created)
我也无法使用以下行进行编码(在本地保存或发送到服务器):
try container.encode(created, forKey: .created)
编译器说:
无法将“时间戳”类型的值转换为预期的参数类型 '字符串'
下面是完整的复制粘贴
此外,时间戳似乎是字典,而不是整数,因为当我尝试将时间戳解码为整数时,我得到了错误:
Expected to decode Int but found a dictionary instead.
但我们都知道 [String:Any](即字典)无法解码。
import FirebaseFirestore
class SomeClassToParseFromFirestoresDatabase: Codable
var created = FirebaseFirestore.Timestamp.init(date: Date())
private enum CodingKeys: String, CodingKey
case created
func encode(to encoder: Encoder) throws
var container = encoder.container(keyedBy: CodingKeys.self)
do
try container.encode(created, forKey: .created)
catch let error
print("error encoding to server or locally: \(error) ")
required init(from decoder: Decoder) throws
let container = try decoder.container(keyedBy: CodingKeys.self)
do
created = try container.decode(FirebaseFirestore.Timestamp.self, forKey: .created)
catch
print("error getting 'created' from server: \(error) ")
下面是一个示例,说明如何解析来自 https.callable firestore 函数(仅返回 JSON)的响应 - 并使用自定义响应类来解析响应中的时间戳(并将时间戳存储在类中)
func getChatUsers( _ done: @escaping (ChatUsersResponse) -> ())
let response = ChatUsersResponse()
response.success = true
let functions = Functions.functions()
functions.httpsCallable("getChatUsers").call
(result, error) in
if let error = error as NSError?
response.success = false
response.message = error.localizedDescription
done(response)
else if let result = result,
let data = result.data as? [String:Any],
let users = data["users"]
do
let nsdata = try JSONSerialization.data(withJSONObject: users, options: .prettyPrinted)
**response.users = try JSONDecoder().decode([SomeClassToParseFromFirestoresDatabase].self, from:nsdata)**
done(response)
catch let error
response.success = false
response.message = error.localizedDescription
done(response)
return
else
response.success = false
response.message = "Server responded with no error, but no users either"
done(response)
【问题讨论】:
【参考方案1】:有点不清楚问题中的代码在做什么,但也许如果我们只是简化流程,它会有所帮助。
这是一个将 Firestore 时间戳写入 'timestamp' 集合的函数,每个文档都有一个唯一的 documentID 和一个 'stamp' 的子字段
func writeTimestampAction()
let now = Date()
let stamp = Timestamp(date: now)
let docRef = self.db.collection("timestamps").document()
docRef.setData( [
"stamp": stamp
])
然后是一个函数,用于从该集合中读取所有时间戳,并以 yyyy-mm-dd 格式将它们输出到控制台。
func readTimestampAction()
self.db.collection("timestamps").getDocuments() (querySnapshot, err) in
if let err = err
print("Error getting documents: \(err)")
else
for document in querySnapshot!.documents
if let stamp = document.get("stamp")
let title = document.documentID
let ts = stamp as! Timestamp
let aDate = ts.dateValue()
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss ZZZ"
let formattedTimeZoneStr = formatter.string(from: aDate)
print(title, formattedTimeZoneStr)
编辑
他是一个可以通过 Firestore 快照的活动类
class ActivityClass
var activity_name = ""
var activity_date: Timestamp?
convenience init(withDoc: QueryDocumentSnapshot)
self.init()
if let stamp = withDoc.get("stamp")
self.activity_date = stamp as? Timestamp
当您从 Firestore 检索数据时,只需执行此操作
for document in querySnapshot!.documents
let myActivity = ActivityClass(withDoc: document)
//do something with myActivity
【讨论】:
谢谢。我想做相反的事情(从 https 可调用响应中将 firestore 时间戳读入本地类) - 我更新了我的帖子 @aman 与什么相反?这个答案演示了如何同时 write 时间戳以及 read 时间戳?如果时间戳存在,只需使用答案的第二部分,一旦您使用let ts = stamp as! Timestamp
读取时间戳,将其存储在您的类中。
对不起,我现在明白了。我想我不明白如何翻译你写的东西 - 它将文档解析为 Swift 的原生 Codable 协议
@aman 我想我的问题是你为什么要使用可编码协议?为什么不直接将 Firestore 返回的快照传递给班级呢?这可能使代码更易于阅读,更易于扩展和维护。我用一个建议更新了我的答案。也许这不是你想去的方向,但它很干净。
@aman 你有没有想过这个问题?我还需要解码 Firestore 时间戳,但无法弄清楚。似乎互联网上没有其他人正在尝试这样做。【参考方案2】:
我需要做两件事。
第一件事是通过使用 timeStamp 的“toString()”在服务器端“设置”我的日期 - 尽管默认情况下它看起来像一个字符串,但时间戳不是一个字符串,并且客户端解析一个空字典。
然后我能够获取该字符串并将其转换为具有以下日期格式的日期
let d = try container.decode(String.self, forKey: .created)
//example: Fri Apr 26 2019 17:25:22
let index = d.index(d.endIndex, offsetBy: -15)
let abc = d[..<index]
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "EEE MMM dd yyyy HH:mm:ss"
if let d = dateFormatter.date(from:String(abc))
created = d
【讨论】:
以上是关于如何快速解码来自 Firebase Firestore 的时间戳的主要内容,如果未能解决你的问题,请参考以下文章
使用 swift Codable 以值作为键来解码 JSON
相同的 Flutter Web 构建使用 `dhttp` 在本地运行,但使用 `firebase serve` 或 `firebase deploy` 失败