You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firebase Firestore返回FIRTimestamp而非Timestamp引发JSON序列化错误

解决Firestore FIRTimestamp无法JSON序列化的问题

问题原因

JSONSerialization仅支持Foundation原生的JSON兼容类型(如字符串、数字、数组、字典等),而FIRTimestamp不属于这类类型,直接序列化会抛出Invalid type in JSON write (FIRTimestamp)错误。你当前代码里的reservations是从Firestore获取的原始对象(包含FIRTimestamp实例),直接用JSONSerialization处理必然报错。

解决方案

方案1:直接用Firestore原生Codable支持(推荐)

Firestore已经内置Codable解码支持,无需通过JSONSerialization中转,直接将文档数据解码为你的ReservationInformation结构体:

// 单个文档解码
func fetchSingleReservation() async throws -> ReservationInformation {
    let docRef = Firestore.firestore().collection("reservations").document("your-doc-id")
    let docSnapshot = try await docRef.getDocument()
    return try docSnapshot.data(as: ReservationInformation.self)
}

// 批量文档解码
func fetchAllReservations() async throws -> [String: ReservationInformation] {
    let querySnapshot = try await Firestore.firestore().collection("reservations").getDocuments()
    var reservations = [String: ReservationInformation]()
    for doc in querySnapshot.documents {
        let reservation = try doc.data(as: ReservationInformation.self)
        reservations[doc.documentID] = reservation
    }
    return reservations
}

方案2:手动转换FIRTimestamp为可序列化类型

如果确实需要生成JSON数据,需先将FIRTimestamp转换为JSON兼容类型(比如时间戳秒数、或包含秒/纳秒的字典),再进行序列化:

// 假设originalReservations是从Firestore拿到的原始字典
var serializableReservations = [String: [String: Any]]()
for (key, reservationDict) in originalReservations {
    var dict = reservationDict
    // 将FIRTimestamp转成秒数(或秒+纳秒的字典)
    if let startTimestamp = dict["start"] as? FIRTimestamp {
        dict["start"] = startTimestamp.seconds
    }
    if let endeTimestamp = dict["ende"] as? FIRTimestamp {
        dict["ende"] = endeTimestamp.seconds
    }
    serializableReservations[key] = dict
}

// 现在可以正常序列化
let jsonData = try JSONSerialization.data(withJSONObject: serializableReservations, options: [])

方案3:自定义Codable处理逻辑

修改ReservationInformation的Codable实现,支持FIRTimestamp与Timestamp的转换:

import FirebaseFirestore

struct ReservationInformation: Codable {
    let flinkeyId: String
    let kennzeichen: String
    let name: String
    let start: Timestamp
    let ende: Timestamp
    
    enum CodingKeys: String, CodingKey {
        case flinkeyId, kennzeichen, name, start, ende
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        flinkeyId = try container.decode(String.self, forKey: .flinkeyId)
        kennzeichen = try container.decode(String.self, forKey: .kennzeichen)
        name = try container.decode(String.self, forKey: .name)
        
        // 处理Firestore返回的FIRTimestamp
        if let firestoreTimestamp = try? container.decode(FIRTimestamp.self, forKey: .start) {
            start = Timestamp(seconds: firestoreTimestamp.seconds, nanoseconds: firestoreTimestamp.nanoseconds)
        } else {
            // 兼容JSON中的秒数格式
            let seconds = try container.decode(Int64.self, forKey: .start)
            start = Timestamp(seconds: seconds, nanoseconds: 0)
        }
        
        // 同理处理ende字段
        if let firestoreTimestamp = try? container.decode(FIRTimestamp.self, forKey: .ende) {
            ende = Timestamp(seconds: firestoreTimestamp.seconds, nanoseconds: firestoreTimestamp.nanoseconds)
        } else {
            let seconds = try container.decode(Int64.self, forKey: .ende)
            ende = Timestamp(seconds: seconds, nanoseconds: 0)
        }
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(flinkeyId, forKey: .flinkeyId)
        try container.encode(kennzeichen, forKey: .kennzeichen)
        try container.encode(name, forKey: .name)
        // 编码为秒数确保JSON兼容
        try container.encode(start.seconds, forKey: .start)
        try container.encode(ende.seconds, forKey: .ende)
    }
}

额外检查项

  • Pod更新后,执行pod install并clean项目(Cmd+Shift+K)后重新编译,确保依赖生效。
  • 确认代码中导入的Timestamp来自import FirebaseFirestore,而非其他同名类型。

内容的提问来源于stack exchange,提问作者Gian Dogwiler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 05:02:05