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