如何处理Swift Date与Firestore Timestamp.dateValue()的精度差异?
Firebase Timestamp与Swift Date转换精度丢失的解决方案
问题复现代码
let timestamp = Timestamp(seconds: 171475088, nanoseconds: 330370000) let dateValue = timestamp.dateValue() let newTimeStamp = Timestamp(date: timestamp.dateValue()) let newDateValue = newTimeStamp.dateValue() print("timestamp: \(timestamp)") print("dateValue: \(dateValue)") print("newTimeStamp: \(newTimeStamp)") print("newDateValue: \(newDateValue)")
运行输出
timestamp: <FIRTimestamp: seconds=171475088 nanoseconds=330370000> dateValue: 1975-06-08 15:58:08 +0000 newTimeStamp: <FIRTimestamp: seconds=171475088 nanoseconds=330369949> newDateValue: 1975-06-08 15:58:08 +0000
转换过程中丢失了51纳秒,看似微小但会影响查询中的日期比较逻辑。具体场景是:每次修改文档时存储lastModifiedDate,需存入UserDefaults,下次启动App时取出并仅获取更新的文档。但无法直接存储Timestamp,将Swift Date存入UserDefaults再转回Timestamp后,isGreaterThan对比会因精度差异失败。除了将Timestamp转为字符串存储,还有其他解决方案吗?
可行解决方案
1. 拆分存储秒数与纳秒数
直接提取Timestamp的seconds和nanoseconds数值分别存入UserDefaults,取出时重新构造完整Timestamp,完全保留原始精度:
// 存储逻辑 let timestamp = Timestamp(seconds: 171475088, nanoseconds: 330370000) UserDefaults.standard.set(timestamp.seconds, forKey: "lastModifiedSeconds") UserDefaults.standard.set(timestamp.nanoseconds, forKey: "lastModifiedNanoseconds") // 取出逻辑 if let seconds = UserDefaults.standard.object(forKey: "lastModifiedSeconds") as? Int64, let nanoseconds = UserDefaults.standard.object(forKey: "lastModifiedNanoseconds") as? Int32 { let restoredTimestamp = Timestamp(seconds: seconds, nanoseconds: nanoseconds) }
2. 编码为Data存储
利用Firebase Timestamp的Codable支持,将其序列化为Data后存入UserDefaults,序列化过程不会丢失精度:
// 存储逻辑 let timestamp = Timestamp(seconds: 171475088, nanoseconds: 330370000) do { let data = try JSONEncoder().encode(timestamp) UserDefaults.standard.set(data, forKey: "lastModifiedTimestamp") } catch { print("编码失败: \(error)") } // 取出逻辑 if let data = UserDefaults.standard.data(forKey: "lastModifiedTimestamp") { do { let restoredTimestamp = try JSONDecoder().decode(Timestamp.self, from: data) } catch { print("解码失败: \(error)") } }
3. 调整查询逻辑容错
如果无法避免精度损失,可以修改查询条件,给时间设置极小的容错阈值,覆盖纳秒级误差:
// 假设从UserDefaults取出的Date转成了有精度损失的timestampWithLoss let thresholdDate = timestampWithLoss.dateValue().addingTimeInterval(-0.001) // 减去1毫秒 let query = db.collection("docs").whereField("lastModifiedDate", isGreaterThan: Timestamp(date: thresholdDate))
这种方式适合对精度要求不是极端严格的场景,避免因微小误差导致查询遗漏。
内容的提问来源于stack exchange,提问作者wshamp
相关产品推荐
相关产品推荐

