Java Date to UTC using gson
Solution 1
After some further research, it appears this is a known issue. The gson default serializer always defaults to your local timezone, and doesn't allow you to specify the timezone. See the following link.....
https://code.google.com/p/google-gson/issues/detail?id=281
The solution is to create a custom gson type adaptor as demonstrated in the link:
// this class can't be static
public class GsonUTCDateAdapter implements JsonSerializer<Date>,JsonDeserializer<Date> {
private final DateFormat dateFormat;
public GsonUTCDateAdapter() {
dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US); //This is the format I need
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); //This is the key line which converts the date to UTC which cannot be accessed with the default serializer
}
@Override public synchronized JsonElement serialize(Date date,Type type,JsonSerializationContext jsonSerializationContext) {
return new JsonPrimitive(dateFormat.format(date));
}
@Override public synchronized Date deserialize(JsonElement jsonElement,Type type,JsonDeserializationContext jsonDeserializationContext) {
try {
return dateFormat.parse(jsonElement.getAsString());
} catch (ParseException e) {
throw new JsonParseException(e);
}
}
}
Then register it as follows :
Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new GsonUTCDateAdapter()).create();
Date now=new Date();
System.out.println(gson.toJson(now));
This now correctly outputs the Date in UTC
"2014-09-25T17:21:42.026Z"
Thanks go to the link author.
Solution 2
The Z in your dateformat is in single-quotes, it must be unquoted to be replaced by the actual timezone.
Furthermore, if you want your date in UTC, convert it first.
Solution 3
The solution that worked for me for this issue was to create a custom Date adapter (P.S be carefull so that you import java.util.Date
not java.sql.Date
!)
public class ColonCompatibileDateTypeAdapter implements JsonSerializer<Date>, JsonDeserializer< Date> {
private final DateFormat dateFormat;
public ColonCompatibileDateTypeAdapter() {
dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ") {
@Override
public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition pos) {
StringBuffer rfcFormat = super.format(date, toAppendTo, pos);
return rfcFormat.insert(rfcFormat.length() - 2, ":");
}
@Override
public Date parse(String text, ParsePosition pos) {
if (text.length() > 3) {
text = text.substring(0, text.length() - 3) + text.substring(text.length() - 2);
}
return super.parse(text, pos);
}
};
}
@Override public synchronized JsonElement serialize(Date date, Type type,
JsonSerializationContext jsonSerializationContext) {
return new JsonPrimitive(dateFormat.format(date));
}
@Override public synchronized Date deserialize(JsonElement jsonElement, Type type,
JsonDeserializationContext jsonDeserializationContext) {
try {
return dateFormat.parse(jsonElement.getAsString());
} catch (ParseException e) {
throw new JsonParseException(e);
}
}}
and then use it while creating GSON object
Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new ColonCompatibileDateTypeAdapter()).create();
Solution 4
I adapted the marked solution and parametrized the DateFormat
:
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Date;
public class GsonDateFormatAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> {
private final DateFormat dateFormat;
public GsonDateFormatAdapter(DateFormat dateFormat) {
this.dateFormat = dateFormat;
}
@Override
public synchronized JsonElement serialize(Date date, Type type, JsonSerializationContext jsonSerializationContext) {
return new JsonPrimitive(dateFormat.format(date));
}
@Override
public synchronized Date deserialize(JsonElement jsonElement, Type type,JsonDeserializationContext jsonDeserializationContext) {
try {
return dateFormat.parse(jsonElement.getAsString());
} catch (ParseException e) {
throw new JsonParseException(e);
}
}
}
Related videos on Youtube
Comments
-
Marky0 almost 2 years
I can't seem to get gson to convert a Date to UTC time in java.... Here is my code...
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").create(); //This is the format I want, which according to the ISO8601 standard - Z specifies UTC - 'Zulu' time Date now=new Date(); System.out.println(now); System.out.println(now.getTimezoneOffset()); System.out.println(gson.toJson(now));
Here is my Output
Thu Sep 25 18:21:42 BST 2014 // Time now - in British Summer Time -60 // As expected : offset is 1hour from UTC "2014-09-25T18:21:42.026Z" // Uhhhh this is not UTC ??? Its still BST !!
The gson result I want and what I was expecting
"2014-09-25T17:21:42.026Z"
I can clearly just subtract 1hr before the call toJson but this seems to be a hack. How can I configure gson to always convert to UTC ?
-
sleeplessnerd over 9 yearsIt is valid ISO8601. If you convert it to UTC first, SimpleDateFormat will put a Z there, otherwise the Offset. docs.oracle.com/javase/7/docs/api/java/text/…
-
sleeplessnerd over 9 yearsSo the Z in the dateFormat should probably be XX
-
Marky0 over 9 yearsWithout the Z in quotes gives "2014-09-25T18:17:21.026+0100" which is the correct time but not UTC. Z without quotes just adds the timezone +0100. I need the output to be the UTC time and read exactly "2014-09-25T17:21:42.026Z"
-
sleeplessnerd over 9 yearsYou have to convert the date object to the UTC timezone first. Can you give gson a DateFormat object instead of a string? since you can tell a SimpleDateFormat object its timezone with
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
-
Michael-O over 9 yearsDon't use
XX
butXXX
only. -
Zapnologica over 7 yearsWhat do I do if I need it to be static?
-
Johann about 6 yearsNot sure why you said the class cannot be static. It can be. I'm using it as a static class.
-
desperateCoder over 4 years
SimpleDateFormat
isn't threadsafe. You could get in big trouble with that... In many cases this shouldn't really have any impact, if you just are aware of this fact. -
VPZ about 4 yearsIf you could extend to include commons-lang3, you can use a thread-safe formatter i.e., FastDateFormat