简体   繁体   English

试图在Swift中将Firebase时间戳转换为NSDate

[英]Trying to convert Firebase timestamp to NSDate in Swift

I'm trying to use Firebase timestamps in a Swift app. 我正在尝试在Swift应用中使用Firebase时间戳。 I'd like to store them in my Firebase, and use them as native NSDate objects in my app. 我想将它们存储在我的Firebase中,并在我的应用中将它们用作本机NSDate对象。

The docs say they are unix epoch time, so I've tried: 文档说他们是unix epoch时间,所以我尝试过:

NSDate(timeIntervalSince1970:FirebaseServerValue.timestamp)

with no luck. 没有运气。

This: 这个:

FirebaseServerValue.timestamp

returns 回报

0x00000001199298a0

according to the debugger. 根据调试器。 What is the best way to pass these timestamps around? 通过这些时间戳的最佳方法是什么?

ServerValue.timestamp() works a little differently than setting normal data in Firebase. ServerValue.timestamp()与在Firebase中设置普通数据的工作方式略有不同。 It does not actually provide a timestamp. 它实际上不提供时间戳。 Instead, it provides a value which tells the Firebase server to fill in that node with the time. 相反,它提供了一个值,告诉Firebase服务器用时间填充该节点。 By using this, your app's timestamps will all come from one source, Firebase, instead of whatever the user's device happens to say. 通过使用此功能,您的应用程序的时间戳将全部来自一个来源Firebase,而不是用户设备所说的任何内容。

When you get the value back (from a observer), you'll get the time as milliseconds since the epoch. 当您获得值(来自观察者)时,您将获得自纪元以来毫秒的时间。 You'll need to convert it to seconds to create an NSDate. 您需要将其转换为秒以创建NSDate。 Here's a snippet of code: 这是一段代码:

let ref = Firebase(url: "<FIREBASE HERE>")

// Tell the server to set the current timestamp at this location.
ref.setValue(ServerValue.timestamp()) 

// Read the value at the given location. It will now have the time.
ref.observeEventType(.Value, withBlock: { 
    snap in
    if let t = snap.value as? NSTimeInterval {
        // Cast the value to an NSTimeInterval
        // and divide by 1000 to get seconds.
        println(NSDate(timeIntervalSince1970: t/1000))
    }
})

You may find that you get two events raised with very close timestamps. 您可能会发现您收到两个非常接近时间戳的事件。 This is because the SDK will take a best "guess" at the timestamp before it hears back from Firebase. 这是因为SDK会在从Firebase收到回复之前对时间戳进行最佳“猜测”。 Once it hears the actual value from Firebase, it will raise the Value event again. 一旦它从Firebase听到实际值,它将再次提升Value事件。

This question is old, but I recently had the same problem so I'll provide an answer. 这个问题很老,但我最近遇到了同样的问题,所以我会提供一个答案。

Here you can see how I am saving a timestamp to Firebase Database 在这里,您可以看到我如何将时间戳保存到Firebase数据库

 let feed = ["userID": uid,
             "pathToImage": url.absoluteString,
             "likes": 0,
             "author": Auth.auth().currentUser!.displayName!,
             "postDescription": self.postText.text ?? "No Description",
             "timestamp": [".sv": "timestamp"],
             "postID": key] as [String: Any]

 let postFeed = ["\(key)" : feed]

 ref.child("posts").updateChildValues(postFeed)

The particularly relevant line of code is "timestamp": [".sv": "timestamp"], 特别相关的代码行是"timestamp": [".sv": "timestamp"],

This saves the timestamp as a double in your database. 这会将时间戳保存为数据库中的double。 This is the time in milliseconds so you need to divide by 1000 in order to get the time in seconds. 这是以毫秒为单位的时间,因此您需要除以1000以获得以秒为单位的时间。 You can see a sample timestamp in this image. 您可以在此图像中看到示例时间戳。 Firebase时间戳

To convert this double into a Date I wrote the following function: 要将此double转换为Date,我编写了以下函数:

func convertTimestamp(serverTimestamp: Double) -> String {
        let x = serverTimestamp / 1000
        let date = NSDate(timeIntervalSince1970: x)
        let formatter = DateFormatter()
        formatter.dateStyle = .long
        formatter.timeStyle = .medium

        return formatter.string(from: date as Date)
    }

This gives a timestamp that looks like this: 这给出了一个如下所示的时间戳: 时间戳

You will get the right time if you use: 如果使用,您将获得正确的时间:

let timestamp = FIRServerValue.timestamp()

let converted = NSDate(timeIntervalSince1970: timestamp / 1000)


let dateFormatter = NSDateFormatter()
dateFormatter.timeZone = NSTimeZone.localTimeZone()
dateFormatter.dateFormat = "hh:mm a"
let time = dateFormatter.stringFromDate(converted)
let serverTimeStamp = ServerValue.timestamp() as! [String:Any]

使用Firebase服务器时间以秒[ktimeStamp:timestamp as AnyObject]Firebase存储类似于[ktimeStamp:timestamp as AnyObject]

let timestampDate = NSDate(timeIntervalSince1970: Double(timestamp as! NSNumber)/1000)

Firestore has an API for this --> -(NSDate *)dateValue Firestore有一个API - > - (NSDate *)dateValue

For example, if you have saved(set) a new document with a field "createdAtDate" 例如,如果您使用字段“createdAtDate”保存(设置)了一个新文档

    NSDictionary *dataToBeSaved = @{
        //Tell the server to save FIRTimestamps when the document is created
        @"createdAtDate":[FIRFieldValue fieldValueForServerTimestamp],
        @"lastModifiedDate":[FIRFieldValue fieldValueForServerTimestamp],

       //Other fields
       @"userName":@"Joe Blow"
    }

    [myFirReference setData:[dataToBeSaved]
                    options:[FIRSetOptions merge]
                 completion:^(NSError* error) {
  }

You can get back this information either with a get query or via setting a listener. 您可以使用get查询或通过设置侦听器来获取此信息。 When you have the snapshot back, just access the dates you saved and convert to NSDate. 恢复快照后,只需访问保存的日期并转换为NSDate。

  NSDate *date1 = [snapshot.data[@"createdAtDate"] dateValue];
  NSDate *date2 = [snapshot.data[@"lastModifiedDate"] dateValue];

There will be a slight loss in precision, but as most people use dates for data synchronization or sorts, I can't think of a case where the loss of precision would be an issue. 精度会略有下降,但由于大多数人使用日期进行数据同步或排序,我无法想到精度损失会成为问题的情况。

For me in swift 5 use in another class: 对于我来说,快速使用另一个类:

import FirebaseFirestore
init?(document: QueryDocumentSnapshot) {
        let data = document.data()
       guard let stamp = data["timeStamp"] as? Timestamp else {
            return nil
        }
       let date = stamp.dateValue()
}

You can create a new transformer for ObjectMapper, 您可以为ObjectMapper创建一个新的转换器,

import Foundation
import ObjectMapper

class FirebaseDateTransform: TransformType {
    public typealias Object = Date
    public typealias JSON = Double

    open func transformFromJSON(_ value: Any?) -> Date? {
        if let millisecondsSince1970 = value as? Double {
            return Date(timeIntervalSince1970: millisecondsSince1970 / 1000.0)
        }

        return nil
    }

    open func transformToJSON(_ value: Date?) -> Double? {
        if let date = value {
            return Double(date.timeIntervalSince1970) * 1000.0
        }

        return nil
    }
}

Gist 要旨

Here is some code, based on alicanbatur's answer, that allows a date to be a Double or a server timestamp, and yet still work within an object mapping layer such as ObjectMapper. 以下是基于alicanbatur的答案的一些代码,它允许日期为Double或服务器时间戳,但仍然可以在对象映射层(如ObjectMapper)中工作。

enum FirebaseDate {
    case date(Date)
    case serverTimestamp

    var date: Date {
        switch self {
        case .date(let date):
            return date
        case .serverTimestamp:
            return Date()
        }
    }
}

class FirebaseDateTransform: TransformType {
    public typealias Object = FirebaseDate
    public typealias JSON = Any

    open func transformFromJSON(_ value: Any?) -> FirebaseDate? {
        switch value {
        case let millisecondsSince1970 as Double:
            let date = Date(millisecondsSince1970: millisecondsSince1970)
            return .date(date)
        case is [AnyHashable: Any]?:
            return .serverTimestamp
        default:
            return nil
        }
    }

    open func transformToJSON(_ value: FirebaseDate?) -> Any? {
        switch value {
        case .date(let date)?:
            return date.millisecondsSince1970
        case .serverTimestamp?:
            return ServerValue.timestamp()
        default:
            return nil
        }
    }
}

You can get a date approximation from Firebase. 您可以从Firebase获取日期近似值。 For example if you're trying to change a firebase user's creation date (a Timestamp) to a Date: 例如,如果您尝试将firebase用户的创建日期(时间戳)更改为日期:

user.creationDate.dateValue()

Swift 4 and updated Firebase library variation of Katfang's answer: Swift 4和Katfang的答案更新了Firebase库的变化:

let currentTimeStamp: TimeInterval?

let ref = Database.database().reference().child("serverTimestamp")

ref.setValue(ServerValue.timestamp())

ref.observe(.value, with: { snap in
    if let t = snap.value as? TimeInterval {
    print(t/1000)
    currentTimeStamp = t/1000
    }
})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM