How to deserialise JSON datetime with nanosecond precision using gson

Viewed 1363

I'm trying to deserialise a JSON object using gson, but having issues when it comes to dates. The date is deserialised from the JSON object, but because the value in the JSON object is in nanoseconds, the value I get is slightly off of the expected value.

See the following code

JSONClass

public class JSONClass {
    private Date timestamp;

    public Date getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(Date timestamp) {
        this.timestamp = timestamp;
    }
}

Main

public class GsonTestApplication {
    public static void main(String[] args) {
        final Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss.SSS").create();
        final String responseJSON = "{ \"timestamp\":\"2017-11-09 11:07:20.079364+00\" }";
        final JSONClass foo = gson.fromJson(responseJSON, new TypeToken<JSONClass>(){}.getType());
        System.out.println(foo.getTimestamp().toString());
    }
}

The output of the application is

Thu Nov 09 11:08:39 GMT 2017

When I expect it to be

Thu Nov 09 11:07:20 GMT 2017

I don't care about the nanosecond precision, so I'm happy for this to be truncated, but as I don't have control over the JSON format, I'm not sure the best way to do this.

How can I get gson to deserialise the date correctly?

1 Answers

This is an issue with the precision available in Date, and with Java 8 it's best to use LocalDateTime. This also means that you will need a TypeAdapter as Gson doesn't work very well with LocalDateTime. This type adapter needs to be registered with Gson to deserialize (and potentially serialize) LocalDateTime objects from Strings.

Something like the below should give you what you need.

JSONClass

public class JSONClass {
    private LocalDateTime timestamp;

    public LocalDateTime getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(LocalDateTime timestamp) {
        this.timestamp = timestamp;
    }
}

LocalDateTimeDeserialiser

static class LocalDateTimeDeserializer implements JsonDeserializer<LocalDateTime> {

        private DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;

        LocalDateTimeDeserializer(String datePattern) {
            this.formatter = DateTimeFormatter.ofPattern(datePattern);
        }

        @Override
        public LocalDateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
            return LocalDateTime.parse(json.getAsString(), formatter);
        }

Main

public class GsonTestApplication {
    public static void main(String[] args) {
        final Gson gson = new GsonBuilder().(LocalDateTime.class, new LocalDateTimeDeserializer("yyyy-MM-dd HH:mm:ss.SSSSSSx")).create();
        final String responseJSON = "{ \"timestamp\":\"2017-11-09 11:07:20.079364+00\" }";
        final JSONClass foo = gson.fromJson(responseJSON, new TypeToken<JSONClass>(){}.getType());
        System.out.println(foo.getTimestamp().toString());
    }
}
Related