Stéphane Piette
Stéphane Piette

Reputation: 5421

GSON - Date format

I'm trying to have a custom date format in Gson output, but .setDateFormat(DateFormat.FULL) doesn't seem to work and it the same with .registerTypeAdapter(Date.class, new DateSerializer()).

It's like Gson doesn't care about the object "Date" and print it in its way.

How can I change that?

Thanks

EDIT:

@Entity
public class AdviceSheet {
  public Date lastModif;
[...]
}

public void method {
   Gson gson = new GsonBuilder().setDateFormat(DateFormat.LONG).create();
   System.out.println(gson.toJson(adviceSheet);
}

I always use java.util.Date; setDateFormat() doesn't work :(

Upvotes: 214

Views: 278190

Answers (8)

Michael-O
Michael-O

Reputation: 18405

This won't really work at all. There is no date type in JSON. I would recommend to serialize to ISO 8601 back and forth (for format agnostics and JS compat). Consider that you have to know which fields contain dates.

Upvotes: 0

Joe Ciaramitaro
Joe Ciaramitaro

Reputation: 106

I'm on Gson 2.8.6 and discovered this bug today.

My approach allows all our existing clients (mobile/web/etc) to continue functioning as they were, but adds some handling for those using 24h formats and allows millis too, for good measure.

Gson rawGson = new Gson();
SimpleDateFormat fmt = new SimpleDateFormat("MMM d, yyyy HH:mm:ss")
private class DateDeserializer implements JsonDeserializer<Date> {
    @Override
    public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
            throws JsonParseException {
        try {
            return new rawGson.fromJson(json, Date.class);
        } catch (JsonSyntaxException e) {}
        String timeString = json.getAsString();
        log.warning("Standard date deserialization didn't work:" + timeString);
        try {
            return fmt.parse(timeString);
        } catch (ParseException e) {}
        log.warning("Parsing as json 24 didn't work:" + timeString);
        return new Date(json.getAsLong());
    }
}

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

I kept serialization the same as all clients understand the standard json date format.

Ordinarily, I don't think it's good practice to use try/catch blocks to govern flow control, but this should be a fairly rare case.

Upvotes: 0

tj-recess
tj-recess

Reputation: 1809

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

Above format seems better to me as it has precision up to millis.

Upvotes: 93

M.L.
M.L.

Reputation: 4706

It seems that you need to define formats for both date and time part or use String-based formatting. For example:

Gson gson = new GsonBuilder()
   .setDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz").create();

or using java.text.DateFormat

Gson gson = new GsonBuilder()
   .setDateFormat(DateFormat.FULL, DateFormat.FULL).create();

or do it with serializers:

I believe that formatters cannot produce timestamps, but this serializer/deserializer-pair seems to work

JsonSerializer<Date> ser = new JsonSerializer<Date>() {
  @Override
  public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext 
             context) {
    return src == null ? null : new JsonPrimitive(src.getTime());
  }
};

JsonDeserializer<Date> deser = new JsonDeserializer<Date>() {
  @Override
  public Date deserialize(JsonElement json, Type typeOfT,
       JsonDeserializationContext context) throws JsonParseException {
    return json == null ? null : new Date(json.getAsLong());
  }
};

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

If using Java 8 or above you should use the above serializers/deserializers like so:

JsonSerializer<Date> ser = (src, typeOfSrc, context) -> src == null ? null
            : new JsonPrimitive(src.getTime());

JsonDeserializer<Date> deser = (jSon, typeOfT, context) -> jSon == null ? null : new Date(jSon.getAsLong());

Upvotes: 351

Marcono1234
Marcono1234

Reputation: 6894

This is a bug. Currently you either have to set a timeStyle as well or use one of the alternatives described in the other answers.

Upvotes: 1

Karthik
Karthik

Reputation: 5040

In case if you hate Inner classes, by taking the advantage of functional interface you can write less code in Java 8 with a lambda expression.

JsonDeserializer<Date> dateJsonDeserializer = 
     (json, typeOfT, context) -> json == null ? null : new Date(json.getAsLong());
Gson gson = new GsonBuilder().registerTypeAdapter(Date.class,dateJsonDeserializer).create();

Upvotes: 5

Abhijit Chakra
Abhijit Chakra

Reputation: 3234

You can specify you format Gson gson = builder.setDateFormat("yyyy-MM-dd").create(); in this method instead of yyyy-MM-dd you can use anyother formats

 GsonBuilder builder = new GsonBuilder();
                        builder.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {
                            public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
                                return new Date(json.getAsJsonPrimitive().getAsLong());
                            }
                        });

                        Gson gson = builder.setDateFormat("yyyy-MM-dd").create();

Upvotes: 2

Milanka
Milanka

Reputation: 1842

As M.L. pointed out, JsonSerializer works here. However, if you are formatting database entities, use java.sql.Date to register you serializer. Deserializer is not needed.

Gson gson = new GsonBuilder()
   .registerTypeAdapter(java.sql.Date.class, ser).create();

This bug report might be related: http://code.google.com/p/google-gson/issues/detail?id=230. I use version 1.7.2 though.

Upvotes: 6

Related Questions