10

I am using Gson to serialize/deserialize my pojos and currently looking for a clean way to tell Gson to parse/output date attributes as unix-timestamps. Here's my attempt:

Gson gson = new GsonBuilder().setDateFormat("U").create();

Comming from PHP where "U" is the dateformat used to serialize/deserialize date as unix-timestamps, when running my attempt code, I am a RuntimeException:

Unknown pattern character 'U'

I am assuming that Gson uses SimpleDateformat under the hood which doesn't define the letter "U".

I could implement a custom DateTypeAdapter but I am looking for a cleaner way to achieve that. Simply changing the DateFormat would be great.

2 Answers2

27

Creating a custom TypeAdapter (UnixTimestampAdapter) was the way to go.

UnixTimestampAdapter

public class UnixTimestampAdapter extends TypeAdapter<Date> {

    @Override
    public void write(JsonWriter out, Date value) throws IOException {
        if (value == null) {
            out.nullValue();
            return;
        }
        out.value(value.getTime() / 1000);
    }

    @Override
    public Date read(JsonReader in) throws IOException {
        if (in.peek() == JsonToken.NULL) {
            in.nextNull();
            return null;
        }
        return new Date(in.nextLong() * 1000);
    }

}

Now, you have to options (depending on your use case):

1 - If you want apply this serialization on all your date fields then register UnixTimestampAdapter upon creating your Gson instance:

Gson gson = new GsonBuilder()
                   .registerTypeAdapter(Date.class, new UnixTimestampAdapter())
                   .create();

2 - Or annotate your date fields with @JsonAdapter (as suggested by @Marcono1234) if you want it applied only to some specific fields.

class Person {
    @JsonAdapter(UnixTimestampAdapter.class)
    private Date birthday;
}
Marcono1234
  • 5,856
  • 1
  • 25
  • 43
  • 1
    Hi, your answer resolves your question at https://github.com/google/gson/issues/987 since ypu have your own solution that is implemented in a true Gson way (not a workaround, that's by design). :) Could you please close the issue? Thanks! – Lyubomyr Shaydariv Mar 15 '17 at 05:42
  • @LyubomyrShaydariv Thanx for reminding me. Your request has been fulfilled. (And you're right sir, that's the way Gson is designed) – Anis LOUNIS aka AnixPasBesoin Mar 15 '17 at 07:29
  • 1
    Ah, and one more note: `JsonReader.toString` returns a human-readable current `JsonReader` state like `JsonReader at line 1 column 1 path $`. There's probably a typo, and `in.nextString()` really does what you need in your code. Or even shorter: `new Date(in.nextLong() / 1000)`. – Lyubomyr Shaydariv Mar 15 '17 at 08:02
  • @LyubomyrShaydariv you're right once again sir. Feel free to make whatever needed correction. This was meant to be "kinda a pseudo-code" to demonstrate how I solved my issue (I'm guilty of not testing it). – Anis LOUNIS aka AnixPasBesoin Mar 15 '17 at 08:13
  • 2
    @AnixPasBesoin you've got a mistake in read override. Must be `return new Date(in.nextLong() * 1000);` The Unix timestamp is in seconds and Date constructor needs milliseconds. – Клаус Шварц Jul 01 '17 at 16:43
  • 1
    As an alternative to registering the adapter with a GsonBuilder you can instead use [`@JsonAdapter`](https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/annotations/JsonAdapter.html) to change serialization and deserialization only for a specific field. – Marcono1234 Oct 29 '21 at 09:57
  • @Marcono1234 if you could post your answer with some code it would be helpful to other ppl! (You'll get my upvote) – Anis LOUNIS aka AnixPasBesoin Oct 29 '21 at 14:02
  • @AnisLOUNIS, you can see an example [here](https://github.com/google/gson/issues/2002#issuecomment-954605978). Feel free to include parts of it in your answer or just mention that `@JsonAdapter` placed on a field is an alternative as well. I don't want to create a separate answer to not compete with yours, which answers the question pretty well. – Marcono1234 Oct 30 '21 at 21:15
-2

Time stamps are just long's, so you can use that in your POJO. Or use Long to get a null if the field is missing.

class myPOJO {
    Long myDate;
}
iagreen
  • 31,470
  • 8
  • 76
  • 90