【问题标题】:How to decode a TimeStamp from the firebase Firestore in swift如何快速解码来自 Firebase Firestore 的时间戳
【发布时间】: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)
      }
    }
  }

【问题讨论】:

    标签: swift firebase timestamp google-cloud-firestore codable


    【解决方案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
      }
    

    【讨论】:

      猜你喜欢
      • 2021-11-23
      • 2019-03-22
      • 1970-01-01
      • 2015-08-20
      • 2020-06-15
      • 2019-09-25
      • 1970-01-01
      • 2019-03-11
      • 2023-03-30
      相关资源
      最近更新 更多