json - How to deserialize a Timestamp as-is using Jackson Annotation in Java? -
i have field in java bean below @jsonformat jackson annotation:
@jsonformat(shape = jsonformat.shape.string, pattern="yyyy-mm-dd hh:mm") private timestamp createdon; when return timestamp, getting converted utc time in json response. lets on formatting timestamp , 2017-09-13 15:30 response getting returned 2017-09-13 10:00.
i know because of jackson annotation default takes system timezone , converts timestamp utc. (in case server belongs asia/calcutta time zone , offset +05:30 , jackson mapper subtracts 5 hrs , 30 minutes convert timestamp utc)
is there way return timestamp as-is, i.e, 2017-09-13 15:30 instead of 2017-09-13 10:00?
i've made test here, changing jvm default timezone asia/calcutta , creating class java.sql.timestamp field:
public class testtimestamp { @jsonformat(shape = jsonformat.shape.string, pattern = "yyyy-mm-dd hh:mm") private timestamp createdon; // getter , setter } in other question told jdk 8 being used, tested in same version (if you're using version (jdk <= 7), check "not java 8" section in bottom). first created timestamp corresponds september 13th 2017, @ 10 in utc:
testtimestamp value = new testtimestamp(); // timestamp corresponds 2017-09-13t10:00:00 utc value.setcreatedon(timestamp.from(instant.parse("2017-09-13t10:00:00z"))); then serialized jackson's objectmapper:
objectmapper om = new objectmapper(); string s = om.writevalueasstring(value); the resulting string is:
{"createdon":"2017-09-13 10:00"}
note that, in generated json, output in utc (10 am). if deserialize json:
value = om.readvalue(s, testtimestamp.class); system.out.println(value.getcreatedon()); this print:
2017-09-13 15:30:00.0
that's because timestamp::tostring() method (which implicity called in system.out.println) prints timestamp in jvm default timezone. in case, default asia/calcutta, , 10 in utc same 15:30 in calcutta, output above produced.
as explained in my answer other question, timestamp object doesn't have timezone information. has number of nanoseconds since unix epoch (1970-01-01t00:00z or "january 1st 1970 @ midnight in utc").
using example above, if see value of value.getcreatedon().gettime(), you'll see it's 1505296800000 - that's number of milliseconds since epoch (to nanoseconds precision, there's method getnanos()).
this milliseconds value corresponds 10 in utc, 7 in são paulo, 11 in london, 7 pm in tokyo, 15:30 in calcutta , on. don't convert timestamp between zones, because millis value same everywhere in world.
what can change, though, representation of value (the corresponding date/time in specific timezone).
in jackson, can create custom serializers , deserializers (by extending com.fasterxml.jackson.databind.jsonserializer , com.fasterxml.jackson.databind.jsondeserializer), can have more control on how format , parse dates.
first create serializer formats timestamp jvm default timezone:
public class timestampserializer extends jsonserializer<timestamp> { private datetimeformatter fmt = datetimeformatter.ofpattern("yyyy-mm-dd hh:mm"); @override public void serialize(timestamp value, jsongenerator gen, serializerprovider serializers) throws ioexception, jsonprocessingexception { // timestmap in default timezone zoneddatetime z = value.toinstant().atzone(zoneid.systemdefault()); string str = fmt.format(z); gen.writestring(str); } } then create deserializer reads date in jvm default timezone , creates timestamp:
public class timestampdeserializer extends jsondeserializer<timestamp> { private datetimeformatter fmt = datetimeformatter.ofpattern("yyyy-mm-dd hh:mm"); @override public timestamp deserialize(jsonparser jsonparser, deserializationcontext ctxt) throws ioexception, jsonprocessingexception { // parse localdatetime localdatetime dt = localdatetime.parse(jsonparser.gettext(), fmt); // date/time in default timezone return timestamp.from(dt.atzone(zoneid.systemdefault()).toinstant()); } } i change field use these custom classes:
// remove jsonformat annotation @jsonserialize(using = timestampserializer.class) @jsondeserialize(using = timestampdeserializer.class) private timestamp createdon; now, when using same timestamp above (that corresponds 2017-09-13t10:00:00z). serializing produces:
{"createdon":"2017-09-13 15:30"}
note output corresponds local time in jvm default timezone (15:30 in asia/calcutta).
when deserializing json, same timestamp (corresponding 10 in utc).
this code uses jvm default timezone, can changed without notice, @ runtime, it's better make explicit 1 you're using.
the api uses iana timezones names (always in format region/city, asia/calcutta or europe/berlin), can create them using zoneid.of("asia/calcutta"). avoid using 3-letter abbreviations (like ist or pst) because ambiguous , not standard.
you can list of available timezones (and choose 1 fits best system) calling zoneid.getavailablezoneids().
if want change output correspond timezone, change zoneid.systemdefault() zone want. keep in mind same zone must used both serialize , deserialize, otherwise you'll wrong results.
not java 8?
if you're using java <= 7, can use threeten backport, great backport java 8's new date/time classes.
the difference package names (in java 8 java.time , in threeten backport org.threeten.bp), classes , methods names same.
there's difference: in java 8 timestamp class has methods toinstant() , from(), you'll need use org.threeten.bp.datetimeutils class make conversions:
public class timestampserializer extends jsonserializer<timestamp> { private datetimeformatter fmt = datetimeformatter.ofpattern("yyyy-mm-dd hh:mm"); @override public void serialize(timestamp value, jsongenerator gen, serializerprovider serializers) throws ioexception, jsonprocessingexception { // timestmap in default timezone zoneddatetime z = datetimeutils.toinstant(value).atzone(zoneid.systemdefault()); string str = fmt.format(z); gen.writestring(str); } } public class timestampdeserializer extends jsondeserializer<timestamp> { private datetimeformatter fmt = datetimeformatter.ofpattern("yyyy-mm-dd hh:mm"); @override public timestamp deserialize(jsonparser jsonparser, deserializationcontext ctxt) throws ioexception, jsonprocessingexception { // parse localdatetime localdatetime dt = localdatetime.parse(jsonparser.gettext(), fmt); // date/time in default timezone return datetimeutils.tosqltimestamp(dt.atzone(zoneid.systemdefault()).toinstant()); } }
Comments
Post a Comment