尝试在 Swift 中将 Firebase 时间戳转换为 NSDate
Trying to convert Firebase timestamp to NSDate in Swift
我正在尝试在 Swift 应用中使用 Firebase 时间戳。我想将它们存储在我的 Firebase 中,并在我的应用程序中将它们用作本机 NSDate 对象。
文档说它们是 unix 纪元时间,所以我试过了:
NSDate(timeIntervalSince1970:FirebaseServerValue.timestamp)
运气不好。
这个:
FirebaseServerValue.timestamp
returns
0x00000001199298a0
根据调试器。传递这些时间戳的最佳方式是什么?
ServerValue.timestamp()
的工作方式与在 Firebase 中设置普通数据略有不同。它实际上并不提供时间戳。相反,它提供了一个值,告诉 Firebase 服务器用时间填充该节点。通过使用它,您应用的时间戳将全部来自一个来源,即 Firebase,而不是用户设备碰巧说的任何内容。
当您(从观察者那里)取回值时,您将获得自纪元以来的毫秒数。您需要将其转换为秒数才能创建 NSDate。这是一段代码:
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))
}
})
您可能会发现引发了两个时间戳非常接近的事件。这是因为 SDK 在从 Firebase 收到回复之前,会在时间戳处取一个最佳值 "guess"。一旦它听到来自 Firebase 的实际值,它将再次引发 Value 事件。
如果您使用:
,您将得到正确的时间
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)
您可以为 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
}
}
这个问题很老了,但我最近遇到了同样的问题,所以我会提供一个答案。
在这里您可以看到我如何将时间戳保存到 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)
特别相关的代码行是"timestamp": [".sv": "timestamp"],
这会将时间戳保存为数据库中的双精度值。这是以毫秒为单位的时间,因此您需要除以 1000 才能获得以秒为单位的时间。您可以在此图像中看到示例时间戳。
为了将这个 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)
}
这给出了如下所示的时间戳:
let serverTimeStamp = ServerValue.timestamp() as! [String:Any]
存储在 Firebase
类似 [ktimeStamp:timestamp as AnyObject]
比使用 Firebase 服务器时间以秒为单位进行转换后:
let timestampDate = NSDate(timeIntervalSince1970: Double(timestamp as! NSNumber)/1000)
这里有一些代码,基于 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
}
}
}
Firestore 对此有一个 API --> -(NSDate *)dateValue
例如,如果您保存(设置)了一个包含字段 "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) {
}
您可以通过获取查询或设置侦听器来取回此信息。当您获得快照后,只需访问您保存的日期并将其转换为 NSDate。
NSDate *date1 = [snapshot.data[@"createdAtDate"] dateValue];
NSDate *date2 = [snapshot.data[@"lastModifiedDate"] dateValue];
精度会有轻微损失,但由于大多数人使用日期进行数据同步或排序,我想不出精度损失会成为问题的情况。
您可以从 Firebase 获得一个近似日期。例如,如果您尝试将 firebase 用户的创建日期(时间戳)更改为日期:
user.creationDate.dateValue()
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
}
})
对我来说 swift 5 在另一个 class 中使用:
import FirebaseFirestore
init?(document: QueryDocumentSnapshot) {
let data = document.data()
guard let stamp = data["timeStamp"] as? Timestamp else {
return nil
}
let date = stamp.dateValue()
}
我正在尝试在 Swift 应用中使用 Firebase 时间戳。我想将它们存储在我的 Firebase 中,并在我的应用程序中将它们用作本机 NSDate 对象。
文档说它们是 unix 纪元时间,所以我试过了:
NSDate(timeIntervalSince1970:FirebaseServerValue.timestamp)
运气不好。
这个:
FirebaseServerValue.timestamp
returns
0x00000001199298a0
根据调试器。传递这些时间戳的最佳方式是什么?
ServerValue.timestamp()
的工作方式与在 Firebase 中设置普通数据略有不同。它实际上并不提供时间戳。相反,它提供了一个值,告诉 Firebase 服务器用时间填充该节点。通过使用它,您应用的时间戳将全部来自一个来源,即 Firebase,而不是用户设备碰巧说的任何内容。
当您(从观察者那里)取回值时,您将获得自纪元以来的毫秒数。您需要将其转换为秒数才能创建 NSDate。这是一段代码:
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))
}
})
您可能会发现引发了两个时间戳非常接近的事件。这是因为 SDK 在从 Firebase 收到回复之前,会在时间戳处取一个最佳值 "guess"。一旦它听到来自 Firebase 的实际值,它将再次引发 Value 事件。
如果您使用:
,您将得到正确的时间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)
您可以为 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
}
}
这个问题很老了,但我最近遇到了同样的问题,所以我会提供一个答案。
在这里您可以看到我如何将时间戳保存到 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)
特别相关的代码行是"timestamp": [".sv": "timestamp"],
这会将时间戳保存为数据库中的双精度值。这是以毫秒为单位的时间,因此您需要除以 1000 才能获得以秒为单位的时间。您可以在此图像中看到示例时间戳。
为了将这个 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)
}
这给出了如下所示的时间戳:
let serverTimeStamp = ServerValue.timestamp() as! [String:Any]
存储在 Firebase
类似 [ktimeStamp:timestamp as AnyObject]
比使用 Firebase 服务器时间以秒为单位进行转换后:
let timestampDate = NSDate(timeIntervalSince1970: Double(timestamp as! NSNumber)/1000)
这里有一些代码,基于 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
}
}
}
Firestore 对此有一个 API --> -(NSDate *)dateValue
例如,如果您保存(设置)了一个包含字段 "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) {
}
您可以通过获取查询或设置侦听器来取回此信息。当您获得快照后,只需访问您保存的日期并将其转换为 NSDate。
NSDate *date1 = [snapshot.data[@"createdAtDate"] dateValue];
NSDate *date2 = [snapshot.data[@"lastModifiedDate"] dateValue];
精度会有轻微损失,但由于大多数人使用日期进行数据同步或排序,我想不出精度损失会成为问题的情况。
您可以从 Firebase 获得一个近似日期。例如,如果您尝试将 firebase 用户的创建日期(时间戳)更改为日期:
user.creationDate.dateValue()
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
}
})
对我来说 swift 5 在另一个 class 中使用:
import FirebaseFirestore
init?(document: QueryDocumentSnapshot) {
let data = document.data()
guard let stamp = data["timeStamp"] as? Timestamp else {
return nil
}
let date = stamp.dateValue()
}