J'essaie d'utiliser les horodatages Firebase dans une application Swift. Je voudrais les stocker dans ma Firebase et les utiliser comme objets NSDate natifs dans mon application.
Les docs disent qu'ils sont du temps Epix unix, j'ai donc essayé:
NSDate(timeIntervalSince1970:FirebaseServerValue.timestamp)
sans chance.
Cette:
FirebaseServerValue.timestamp
retour
0x00000001199298a0
selon le débogueur. Quelle est la meilleure façon de faire circuler ces horodatages?
ServerValue.timestamp()
fonctionne un peu différemment de la définition de données normales dans Firebase. Il ne fournit pas réellement d'horodatage. Au lieu de cela, il fournit une valeur qui indique au serveur Firebase de remplir ce nœud avec l'heure. En l'utilisant, les horodatages de votre application proviendront tous d'une seule source, Firebase, au lieu de ce que l'appareil de l'utilisateur dit.
Lorsque vous récupérez la valeur (d'un observateur), vous obtenez le temps en millisecondes depuis l'époque. Vous devrez le convertir en secondes pour créer une NSDate. Voici un extrait de 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))
}
})
Vous pouvez constater que vous obtenez deux événements déclenchés avec des horodatages très proches. Cela est dû au fait que le SDK prendra une meilleure "estimation" à l'horodatage avant qu'il n'entende de Firebase. Une fois qu'il entend la valeur réelle de Firebase, il déclenche à nouveau l'événement Value.
Cette question est ancienne, mais j'ai récemment eu le même problème, je vais donc y répondre.
Ici, vous pouvez voir comment j'enregistre un horodatage dans la base de données 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)
La ligne de code particulièrement pertinente est "timestamp": [".sv": "timestamp"],
Cela enregistre l'horodatage sous forme de double dans votre base de données. C'est le temps en millisecondes, vous devez donc diviser par 1000 afin d'obtenir le temps en secondes. Vous pouvez voir un exemple d'horodatage dans cette image.
Pour convertir ce double en une date, j'ai écrit la fonction suivante:
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)
}
Vous obtiendrez le bon moment si vous utilisez:
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)
Pour moi en Swift 5 utilisez dans une autre classe:
import FirebaseFirestore
init?(document: QueryDocumentSnapshot) {
let data = document.data()
guard let stamp = data["timeStamp"] as? Timestamp else {
return nil
}
let date = stamp.dateValue()
}
let serverTimeStamp = ServerValue.timestamp() as! [String:Any]
Stocker dans Firebase
quelque chose comme [ktimeStamp:timestamp as AnyObject]
qu'après avoir converti en quelques secondes à l'aide de Firebase Server Time:
let timestampDate = NSDate(timeIntervalSince1970: Double(timestamp as! NSNumber)/1000)
Firestore possède une API pour cette -> - (NSDate *) dateValue
Par exemple, si vous avez enregistré (défini) un nouveau document avec un champ "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) {
}
Vous pouvez récupérer ces informations soit avec une requête get, soit via la définition d'un écouteur. Lorsque vous avez récupéré l'instantané, accédez simplement aux dates que vous avez enregistrées et convertissez-les en NSDate.
NSDate *date1 = [snapshot.data[@"createdAtDate"] dateValue];
NSDate *date2 = [snapshot.data[@"lastModifiedDate"] dateValue];
Il y aura une légère perte de précision, mais comme la plupart des gens utilisent des dates pour la synchronisation ou le tri des données, je ne peux pas penser à un cas où la perte de précision serait un problème.
Voici un code, basé sur la réponse d'alicanbatur, qui permet à une date d'être un horodatage Double ou serveur, tout en fonctionnant dans une couche de mappage d'objet telle que 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
}
}
}
Vous pouvez créer un nouveau transformateur pour 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
}
}
Swift 4 et la version mise à jour de la bibliothèque Firebase de la réponse de Katfang:
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
}
})
Vous pouvez obtenir une approximation de la date à partir de Firebase. Par exemple, si vous essayez de changer la date de création d'un utilisateur Firebase (un horodatage) en une date:
user.creationDate.dateValue()