Firestore Server Timestamp (Kotlin)

March 1, 2019
FieldValue.serverTimestamp() or @ServerTimestamp

Why use server timestamp?

The local datetime could be inaccurate (device accidentally change to wrong timezone, time not syncing with external server for long time or intentional change of clock time).

If we use a local time, it could be a future date by accident. Imagine we sort by using local date in descending order, the future date object will always show up first (imagined the future date is one year ahead).

Server Timestamp offer reliable sorting on server-side.

Why don’t use server timestamp

Server timestamp require access to backend server, which doesn’t work when the device is offline.

If you sort by server timestamp when the device if offline, the date shall be null and the sort order is unpredictable.

Local timestamp is required for offline sorting on client side.

Firestore Server Timestamp

Insert server timestamp via FieldValue.serverTimestamp().

val db = FirebaseFirestore.getInstance()

db.collection("test")
    .add(mapOf(
        "created" to FieldValue.serverTimestamp(),
        "posted_date" to Timestamp.now()
    ))
    .addOnSuccessListener {
        val id = it.id

        it.get().addOnSuccessListener { document ->
            val id = document.id
            val created = document.getDate("created")
            val postedDate = document.getDate("posted_date")
            Timber.d("id=$id, created=$created, postedDate=$postedDate")
        }
    }
id=euvr10lwtinNT66xJBxB, created=Fri Mar 01 18:29:58 GMT+08:00 2019, postedDate=Fri Mar 01 18:29:58 GMT+08:00 2019

Insert server timestamp via @ServerTimestamp using custom POJO object.

class Test(
    @get:PropertyName(CREATED)
    @set:PropertyName(CREATED)
    @ServerTimestamp var created: Timestamp? = null,
    @get:PropertyName(POSTED_DATE)
    @set:PropertyName(POSTED_DATE)
    var postedDate: Timestamp? = Timestamp.now()) {

    companion object {
        const val COLLECTION_NAME = "test"

        const val CREATED = "created"
        const val POSTED_DATE = "posted_date"
    }
}
val db = FirebaseFirestore.getInstance()

val item = Test()

db.collection(Test.COLLECTION_NAME)
    .add(item)
    .addOnSuccessListener {
        val id = it.id

        it.get().addOnSuccessListener { document ->
            val item = document.toObject(Test::class.java)

            val id = document.id
            if (item != null) {
                val created = item.created?.toDate()
                val postedDate = item.postedDate?.toDate()
                Timber.d("id=$id, created=$created, postedDate=$postedDate")
            }
        }
    }
id=6CCqsILuj9MOcAZGoXBh, created=Fri Mar 01 18:41:39 GMT+08:00 2019, postedDate=Fri Mar 01 18:41:39 GMT+08:00 2019

NOTE: when device is offline, addOnSuccessListener would not be called, and server timestamp shall be null. Refer to Firestore Offline Behaviour

This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.