Home » Android » android – Retrofit GSON serialize Date from json string into long or java.lang.Long

android – Retrofit GSON serialize Date from json string into long or java.lang.Long

Posted by: admin June 15, 2020 Leave a comment

Questions:

I am using the Retrofit library for my REST calls.
The JSON that is coming in looks like this.

{
    "created_at": "2013-07-16T22:52:36Z",
} 

How can I tell Retrofit or Gson to convert this into long?

How to&Answers:

You can easily do this by setting a custom GsonConverter with your own Gson object on the retrofit instance. In your POJO you can Date created_at; instead of a long or a String. From the date object you can use created_at.getTime() to get the long when necessary.

Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssz")
.create();

RestAdapter.Builder builder = new RestAdapter.Builder();
// Use a custom GSON converter
builder.setConverter(new GsonConverter(gson));
..... create retrofit service.

You can also support multiple Date string formats by registering a custom JsonDeserializer on the gson instance used by retrofit

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Date.class, new DateTypeDeserializer());

public class DateTypeDeserializer implements JsonDeserializer<Date> {
    private static final String[] DATE_FORMATS = new String[]{
            "yyyy-MM-dd'T'HH:mm:ssZ",
            "yyyy-MM-dd'T'HH:mm:ss",
            "yyyy-MM-dd",
            "EEE MMM dd HH:mm:ss z yyyy",
            "HH:mm:ss",
            "MM/dd/yyyy HH:mm:ss aaa",
            "yyyy-MM-dd'T'HH:mm:ss.SSSSSS",
            "yyyy-MM-dd'T'HH:mm:ss.SSSSSSS",
            "yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'",
            "MMM d',' yyyy H:mm:ss a"
    };

    @Override
    public Date deserialize(JsonElement jsonElement, Type typeOF, JsonDeserializationContext context) throws JsonParseException {
        for (String format : DATE_FORMATS) {
            try {
                return new SimpleDateFormat(format, Locale.US).parse(jsonElement.getAsString());
            } catch (ParseException e) {
            }
        }
        throw new JsonParseException("Unparseable date: \"" + jsonElement.getAsString()
                + "\". Supported formats: \n" + Arrays.toString(DATE_FORMATS));
    }
}

Answer:

Read it in as a string in your POJO then use your getter to return it as a long:

String created_at;

public long getCreatedAt(){
    SimpleDateFormat formatter = new 
              SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
    Date createDate = formatter.parse(created_at);

    return createDate.getTime();
 }

the SimpleDateFormat string can be referenced here

Answer:

After reading the docs, I tried this. It works but i dont know if it will have any effect on other types.

I needed to have a long in my POJO, coz i dont wanna convert when saving into db.

I used a custom deserializer

JsonDeserializer<Long> deserializer = new JsonDeserializer<Long>() {
    @Override
    public Long deserialize(JsonElement json, Type typeOfT,
        JsonDeserializationContext context) throws JsonParseException {
        try{
            if(json==null){
               return new Long(0);
            }
            else{
                String dateString = json.getAsString();
                long dateLong = DateFormatUtil.getLongServerTime(dateString);
                return new Long(dateLong);
            }
        }
        catch(ParseException e){
            return new Long(0);
        }
    }
};

and using it

Gson gson = new GsonBuilder()
    .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
    .setDateFormat(patternFromServer)
    .registerTypeAdapter(Long.class, deserializer)
    .create();

Answer:

You could simply use this setDateFormat() method to do it

public class RestClient
{
    private static final String BASE_URL = "your base url";
    private ApiService apiService;

    public RestClient()
    {
        Gson gson = new GsonBuilder()
                .setDateFormat("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'SSS'Z'")
                .create();

        RestAdapter restAdapter = new RestAdapter.Builder()
                .setLogLevel(RestAdapter.LogLevel.FULL)
                .setEndpoint(BASE_URL)
                .setConverter(new GsonConverter(gson))
                .build();

        apiService = restAdapter.create(ApiService.class);
    }

    public ApiService getApiService()
    {
        return apiService;
    }
}

Answer:

Below code is tested and finally working after lot efforts.
before creating retrofit object create Gson object

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

and now create retrofit instance

 Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("URL")
                    .addConverterFactory(GsonConverterFactory.create(gson))
                    .build();

create these two classes to serialize and deserialize date format

static class DateDeserializer implements JsonDeserializer<Date> {

        private final String TAG = DateDeserializer.class.getSimpleName();

        @Override
        public Date deserialize(JsonElement element, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
            String date = element.getAsString();

            SimpleDateFormat formatter = new SimpleDateFormat(DATE_FORMAT);
            formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
            Date returnDate = null;
            try {
                returnDate = formatter.parse(date);
            } catch (ParseException e) {
                Log.e(TAG, "Date parser exception:", e);
                returnDate = null;
            }
            return returnDate;
        }
    }

    static class DateSerializer implements JsonSerializer<Date> {

        private final String TAG = DateSerializer.class.getSimpleName();

        @Override
        public JsonElement serialize(Date date, Type type, JsonSerializationContext jsonSerializationContext) {
            SimpleDateFormat formatter = new SimpleDateFormat(DATE_FORMAT);
            formatter.setTimeZone(TimeZone.getDefault());
            String dateFormatAsString = formatter.format(date);
            return new JsonPrimitive(dateFormatAsString);
        }

    }

Answer:

You can set the parse pattern in the GsonBuilder.setDateFormat() and set Date object in the POJO and then just call Date.getMillis()

setDateFormat()

Answer:

You should be using a type adapter in your Gson instance through

new GsonBuilder()
    .registerTypeAdapter(Date.class, [date deserializer class here])
    .create

But can I suggest that instead of using a SimpleDateFormatter you take a look at this implementation from FasterXML/jackson-databind implementations for ISO8601 date handling in this class and this one. It very much depends on whether you are parsing a lot of dates or not.

Also note that we ran into issues with using SimpleDateFormatter inside an Android application (we use a combination of Java and Android libraries) where there were different results between parsing in Java and Android. Using the above implementations helped to solve this issue.

This is the Java implementation and this is the Android implementation, not the definition for Z and X in the Java implementation and the missing X implementation in Android