2

I noticed that the downloaded timestamps of objects that are created by FIRServerValue.timestamp() are slightly different than the online version. My code:

    let messagesRef = self.ref.child("messages").child(chatId)
    messagesRef
        .queryOrderedByChild("timestamp")
        .queryLimitedToLast(500)
        .observeEventType(.ChildAdded, withBlock: { (snapshot) -> Void in

            guard let object = snapshot.value as? [String: AnyObject] else { return }

            let messageId = snapshot.key

            if let
                senderId = object["senderId"] as? String,
                senderName = object["senderName"] as? String,
                senderEmail = object["senderEmail"] as? String,
                timestamp = object["timestamp"] as? NSTimeInterval {

                let date = timestamp.toDate()
                let text = object["text"] as? String

                print("text: \(text) - timestamp: \(timestamp)")
            }
    })

Here is a sample output compared to the online value (marked by ->):

text: Optional("1") - timestamp: 1471596374007.0 -> 1471596374874
text: Optional("2") - timestamp: 1471596375044.0 -> 1471596375324
text: Optional("3") - timestamp: 1471596376157.0 -> 1471596376461
text: Optional("4") - timestamp: 1471596461213.0 -> 1471596463220
text: Optional("5") - timestamp: 1471596542659.0 -> 1471596543307

I sometimes encounter a bug where a messages comes before another message, even though it has been sent after that particular message. I assume it has something to do with this behaviour. When the retrieved timestamps are not exact, messages that are sent close to each other in time, can be ordered differently.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
MJQZ1347
  • 2,607
  • 7
  • 27
  • 49
  • What do you mean by "online value"? – cartant Aug 19 '16 at 09:13
  • The value saved to the realtime database. – MJQZ1347 Aug 19 '16 at 10:13
  • So the "online value" is the value you see in the Firebase console? Are the `ChildAdded` events that contain the `timestamps` that differ from the "online values" firing when you create a new message or when you read existing messages? – cartant Aug 19 '16 at 11:17
  • Yes, I was reffering to the values stored in the Firebase console. Regarding your question about `ChildAdded`: I just checked that when the messages are created on another device the retrieved `timestamps` are in fact equal to the online versions. However, when they are sent from the same device, the small differences show up. Maybe it is because of `FIRDatabase.database().persistenceEnabled = true`? BTW: The messages are saved by calling `setValue` on the messages ref. **Edit:** Nope, disabling the persistence didn't help. The problem still occurs. – MJQZ1347 Aug 19 '16 at 11:28

1 Answers1

3

According to the documentation, when you specify the server timestamp the data sent to the server contains a:

Placeholder value for the number of milliseconds since the Unix epoch.

That placeholder will be replaced with the server's timestamp. However, if you have ChildAdded listeners on the devices that add data, those listeners are notified locally - and that's going to involve replacing the placeholder with a local timestamp. I suspect that's why you are seeing a difference between what's reported via the listener - when a message is written - and what shows up on the console. And that's also why the values that are read match those that are shown in the console.

Firebase likely takes into account the offset between the local and server clocks - as it accounts for this in the generation of keys for pushed data - but you are still going to get a small difference because the data is going to take some time to get to the server.

This local firing of events is also the reason you might sometimes see ChildAdded event firing in an unexpected order. I answered a question regarding unexpected snapshot ordering a few days ago.

Community
  • 1
  • 1
cartant
  • 57,105
  • 17
  • 163
  • 197
  • 2
    The solution for the problem is to not only respond to `.ChildAdded`, but also to `.ChildChanged`. See my answer to this question for a step-by-step explanation of the flow: http://stackoverflow.com/questions/37864974/how-to-use-the-firebase-server-timestamp-to-generate-date-created – Frank van Puffelen Aug 19 '16 at 14:45