web-dev-qa-db-fra.com

Essayer de convertir l'horodatage Firebase en NSDate dans Swift

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?

18
Fook

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.

36
katfang

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. Firebase Timestamp

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)
    }

Cela donne un horodatage qui ressemble à ceci: Timestamp

7
DoesData

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)
3
TAREK

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()
}
1
Raul Quispe
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)
1
Nikhil Jobanputra

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.

1
Mike Critchley

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
        }
    }
}
0
phatmann

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
    }
}

Gist

0
alicanbatur

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
    }
})
0
Aaron Halvorsen

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()
0
Noodybrank