如何快速解码来自 firebase Firestore 的时间戳

ama*_*man 3 timestamp firebase swift codable google-cloud-firestore

我想通过解析 firestore 数据库的响应来解码时间戳(由 FirebaseFirestore.Timestamp 在 swift 中定义)。

编译器告诉我从服务器解析以下代码:

实例方法“decode(_:forKey:)”要求“Timestamp”符合“Decodable”

 created = try container.decode(FirebaseFirestore.Timestamp.self, forKey: .created)
Run Code Online (Sandbox Code Playgroud)

我也无法使用以下行进行编码(在本地保存或发送到服务器):

try container.encode(created, forKey: .created)
Run Code Online (Sandbox Code Playgroud)

编译器说:

无法将“Timestamp”类型的值转换为预期的参数类型“String”

完整的复制粘贴如下

另外,时间戳似乎是字典,而不是整数,因为当我尝试将时间戳解码为整数时,出现错误:

Expected to decode Int but found a dictionary instead.
Run Code Online (Sandbox Code Playgroud)

但我们都知道 [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) ")
    }
  }
}

Run Code Online (Sandbox Code Playgroud)

下面是如何解析来自 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)
      }
    }
  }
Run Code Online (Sandbox Code Playgroud)

Jay*_*Jay 6

有点不清楚问题中的代码在做什么,但也许如果我们只是简化过程,它会有所帮助。

这是一个将 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
    ])
}
Run Code Online (Sandbox Code Playgroud)

然后是一个从该集合中读取所有时间戳并以 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)

                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑

他是一个可以通过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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当您从 Firestore 检索数据时,只需执行以下操作

for document in querySnapshot!.documents {
   let myActivity = ActivityClass(withDoc: document)
   //do something with myActivity
Run Code Online (Sandbox Code Playgroud)