1

I've followed this Stackoverflow post and there is clearly said how to store the timestamp, if we user the ServerTimestamp annotation. However, I want to ask about other alternatives, which can later also be used to perform queries on them.

With respect to the different time libraries (before/after Java 8) we can get the timestamp as a long variables, or as ZonedDateTime object. My question is:

Can we save ZonedDateTime object or a long variable as a String and then perform queries on it, or we must use in any case ServerTimestamp annotation?

H.Karatsanov
  • 199
  • 4
  • 16

2 Answers2

0

If you want to write a timestamp field, and you can't use a server timestamp, you will need to either provide a regular Java Date object, or a Firebase Timestamp object. Either of these types of values will convert to a timestamp field in the document.

When you query for the document, the field will always show up in the document snapshot as a Timestamp type object.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • Okay. So only those two are accepted by Firebase? (I'm asking because articles say to avoid objects like Date, SimpleDateType, or maybe I've misunderstood it) – H.Karatsanov Jul 02 '20 at 20:59
  • Just Date and Timestamp. You will have to convert to one of those. I suggest just giving it a try. – Doug Stevenson Jul 02 '20 at 22:03
  • Thank you! I will do! – H.Karatsanov Jul 02 '20 at 22:05
  • 1
    @H.Karatsanov While `java.sql.Timestamp` is a poorly designed and long outdated class (a true hack on top of the already poorly designed `java.util.Date`), the firebase `Timestamp` class is newer. I don’t know it, but I would expect that it doesn’t share the bad traits of the `java.sql` type. – Ole V.V. Jul 04 '20 at 16:43
  • 1
    @OleV.V. you're right. But since Firebase works only with Date, we need to take the LocalDateTime(ThreeTen.., java.time) and then parse it to Date, in order for Firebase to accept it. I will write the answer for it with code later – H.Karatsanov Jul 04 '20 at 16:51
0

I've figured it out. As you know when we're dealing with Time in Android, we need to pay attention to the different APIs i.e. APIs before API 26 and after that. There are many articles for this topic in Stackoverflow, but generalized, before Android 8 (Oreo, API 26) we need to use the library ThreeTenABP and after Android 8 we need to use java.time.

An implementation looks like this:

private Date getCurrentDate(){
        if(Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O){
            return Date.from(Instant.now());
        } else {
            AndroidThreeTen.init(this);
            return DateTimeUtils.toDate(org.threeten.bp.Instant.now());
        }
    }

Of course, you can use LocalDateTime or ZonedDateTime etc.

Firebase expects Date object, or you can use the @ServerTimestamp annotation and provide no parameter in the constructor of your model. Firebase will then create the timestamp when request for saving data comes to it. Like this

//When you provide Date 
class SomeClass {
   private String someAttribute;
   private Date someDate;
   ...
   public SomeClass(String someAttribute, Date someDate, ...){
     this.someAttribute = someAttribute;
     this.someDate = someDate;

   }
}

//When you don't provide Date 
class SomeClass {
   private String someAttribute;
   private @ServerTimestamp Date someDate;
   ...
   public SomeClass(String someAttribute, ...){
     this.someAttribute = someAttribute;
    ...
   }
}

(In may case I needed the Date object when I start an activity, but a request to the server may happen even after 2-3 hours. That's why @ServerTimestamp was inefficient for me.)

The retrieving happens in the same way. Create a model class, or use HashMap (your choice) but the type must be Date. It holds almost every kind of information according to date and time (time zone, the time is even up to microseconds etc).

Most of the time, the user wants to see only a date and a time in form of hours:minutes. You can use DateTimeFormatter and provide the pattern which you want (there are plenty of standards). In my case I use it in this way:

private String formatDate(Date date){
        if(Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O){
            java.time.LocalDateTime ldt = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
            java.time.format.DateTimeFormatter dtf = java.time.format.DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm");
            return ldt.format(dtf);
        } else {
            LocalDateTime ldt = Instant.ofEpochMilli(date.getTime()).atZone(org.threeten.bp.ZoneId.systemDefault()).toLocalDateTime();
            DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm");
            return ldt.format(dtf);
        }
    }

As you see the method expects a Date object (what you retrieve from Firebase). Then it will remove most of the irrelevant data (in my case) and return you only the date and the time in the specified format.

(Note: in this post where UPDATE 2020/01/17 is, a colleague points that with Android Studio 4.0 we can use Java 8 in older APIs as well (like in my case - API 21), but I didn't dig into the topic concrete. You can check it also :)

H.Karatsanov
  • 199
  • 4
  • 16