Reputation: 6284
Currently, the Google's version of ServerValue.TIMESTAMP
returns {".sv":"timestamp"}
which is used as a directive for Firebase to fill that field with the server timestamp once you save the data to the Firebase server.
When you create your data on the client side however, you don't have the actual timestamp to play with yet (ie. use as the creation date). You only will have an access to the timestamp after the initial save and consequent retrieval, which - I imagine - is sometimes too late and not very elegant.
Before Google:
Update: Ignore this section as it is incorrect - I misunderstood the examples. ServerValue.TIMESTAMP
always returned the {".sv":"timestamp"}
.
As far as I understand in pre-google Firebase there seemed to be a server-generated timestamp available that allowed you to acquire the actual timestamp:
import com.firebase.client.ServerValue;
ServerValue.TIMESTAMP // eg. 1466094046
Questions:
Note:
I'm not considering using new Date()
on client side as I've been reading it's not safe, though please share your thoughts if you think different.
Upvotes: 22
Views: 43501
Reputation: 598797
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:
ServerValue.TIMESTAMP
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.
Upvotes: 30
Reputation: 3999
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. ;)
Upvotes: 3