How to use the Firebase server timestamp to generate date created?

When you use the ServerValue.TIMESTAMP constant in a write operation, you're saying that the Firebase Database server should determine the correct timestamp when it executes the write operation.

Let's say we run this code:

ref.addValueEventListener(new ValueEventListener() {
    public void onDataChange(DataSnapshot dataSnapshot) {
        System.out.println(dataSnapshot.getValue()); 
    }

    public void onCancelled(DatabaseError databaseError) { }
});
ref.setValue(ServerValue.TIMESTAMP);

This will execute as follows:

  1. you attach a listener
  2. you write a value with ServerValue.TIMESTAMP
  3. the Firebase client immediate fires a value event with an approximation of the timestamp it will write on the server
  4. your code prints that value
  5. the write operation gets sent to the Firebase servers
  6. the Firebase servers determine the actual timestamp and write the value to the database (assuming no security rules fail)
  7. the Firebase server send the actual timestamp back to the client
  8. the Firebase client raises a value event for the actual value
  9. your code prints that value

If you're using ChildEventListener instead of a ValueEventListener, then the client will call onChildAdded in step 3 and onChildChanged in step 8.

Nothing changed in the way we generate the ServerValue.TIMESTAMP since Firebase joined Google. Code that worked before, will continue to work. That also means that the first answer you linked is a valid way to handle it.


I'm doing it a bit differently.

Solution 1: push() method in POJO

As I don't want to clutter my POJOs with strange getters or properties, I'm just defining a push() method inside my POJOs which looks like this:

/**
 * Pushes a new instance to the DB.
 * 
 * @param parentNode `DatabaseReference` to the parent node this object shall be attached to
 */
fun push(parentNode: DatabaseReference) {
    parentNode
        .push()
        .apply {
            setValue(this@Pojo)
            child(Pojo.CREATED_AT_KEY).setValue(ServerValue.TIMESTAMP)
        }
}

Then I can simply create an instance of the POJO and call push() on it which properly populates the creation time property.

This definitely makes the POJO a little less plain and involves logic a POJO shouldn't know about. However using @Exclude annotations and/or casts as outlined in some of the responses here also requires knowledge of the storing mechanism.

Solution 2: Helper or DatabaseReference extension (Kotlin)

To overcome this you can of course also just create a pushTask(task: Task) method in a helper or - if using Kotlin - an extension method to e.g. DatabaseReference which could look like this:

fun DatabaseReference.push(pojo: Pojo) {
    push()
    .apply {
        setValue(pojo)
        child(Pojo.CREATED_AT_KEY).setValue(ServerValue.TIMESTAMP)
    }
}

Looking at it now I come to think that I actually like the second approach more (if I have Kotlin at my disposal - I don't like helpers). But this is probably just a matter of taste. ;)