How do I deserialize timestamps that are in seconds with Jackson?
Solution 1
I wrote a custom deserializer to handle timestamps in seconds (Groovy syntax).
class UnixTimestampDeserializer extends JsonDeserializer<DateTime> {
Logger logger = LoggerFactory.getLogger(UnixTimestampDeserializer.class)
@Override
DateTime deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
String timestamp = jp.getText().trim()
try {
return new DateTime(Long.valueOf(timestamp + '000'))
} catch (NumberFormatException e) {
logger.warn('Unable to deserialize timestamp: ' + timestamp, e)
return null
}
}
}
And then I annotated my POGO to use that for the timestamp:
class TimestampThing {
@JsonDeserialize(using = UnixTimestampDeserializer.class)
DateTime timestamp
@JsonCreator
public TimestampThing(@JsonProperty('timestamp') DateTime timestamp) {
this.timestamp = timestamp
}
}
Solution 2
@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="s")
public Date timestamp;
edit: vivek-kothari suggestion
@JsonFormat(shape=JsonFormat.Shape.NUMBER, pattern="s")
public Timestamp timestamp;
Solution 3
A very similar approach to that of @DrewStephens's which uses the Java SE TimeUnit
API (introduced in JDK1.5
) instead of plain String concatenation and is thus (arguably) a little bit cleaner and more expressive:
public class UnixTimestampDeserializer extends JsonDeserializer<Date> {
@Override
public Date deserialize(JsonParser parser, DeserializationContext context)
throws IOException, JsonProcessingException {
String unixTimestamp = parser.getText().trim();
return new Date(TimeUnit.SECONDS.toMillis(Long.valueOf(unixTimestamp)));
}
}
Specifying your custom deserializer (UnixTimestampDeserializer
) on the affected Date
field(s):
@JsonDeserialize(using = UnixTimestampDeserializer.class)
private Date updatedAt;
Solution 4
I had this exact issue, except my ZonedDateTime objects got turned to unix-timestamps (seconds) and I needed them in milliseconds (to initialize JS Date objects on the browser).
Implementing a custom serializer/deserializer looked like too much work for something that should be pretty straightforward, so I looked elsewhere and found that I can just configure the object mapper for the desired result.
Because my application already overrides the default ObjectMapper provided by Jersey, I just had to disable SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS
.
Here's my code
@Provider
public class RPObjectMapperProvider implements ContextResolver<ObjectMapper> {
final ObjectMapper defaultObjectMapper;
public RPObjectMapperProvider() {
defaultObjectMapper = new ObjectMapper();
// this turned ZonedDateTime objects to proper seconds timestamps
defaultObjectMapper.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// disable to serialize dates for millis timestamps
defaultObjectMapper.disable(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS);
// using Java8 date time classes
defaultObjectMapper.registerModule(new JavaTimeModule());
}
@Override
public ObjectMapper getContext(Class<?> type) {
return defaultObjectMapper;
}
}
And that's it
Comments
-
Drew Stephens almost 4 years
I've got some JSON that has timestamps in seconds (i.e. a Unix timestamp):
{"foo":"bar","timestamp":1386280997}
Asking Jackson to deserialize this into an object with a DateTime field for the timestamp results in
1970-01-17T01:11:25.983Z
, a time shortly after the epoch because Jackson is assuming it to be in milliseconds. Aside from ripping apart the JSON and adding some zeros, how might I get Jackson to understand the seconds timestamp? -
sherpya over 9 yearswhy downvote? because it is easier than other solutions?
-
Renaud Cerrato about 9 yearsprobably because its timestamps are represented as
integer
and not asstring
in json. -
sherpya about 9 yearsjackson does required type conversion
-
Renaud Cerrato about 9 years
{"timestamp" : "42"}
is not the same as{"timestamp" : 42}
, and I'm assuming that yourJsonFormat
will expect double quotes around. -
sherpya about 9 yearslooks like jackson does automatic type conversion using the field type and not the intermediate data type used by formatter
-
Ralph almost 9 yearsThis does not work, because it {{s}} mean not the seconds since 1970, it mean the seconds of the "given" date (0..59)
-
tuscland over 8 yearsHello, just out of curiousity what dialect of Java is it? Thanks!
-
thomi over 8 yearsWorks like a charm in ordinary boring java, too. Just use the Annotation on whatever DateTime field you need. Did not try using Java 8 Date, but should be no problem there either. Thanks
-
Jan Papenbrock over 7 yearsI used
NUMBER_INT
instead ofNUMBER
to get rid of decimal places - so in full:@JsonFormat(shape=JsonFormat.Shape.NUMBER_INT, pattern="s")
-
acheron55 over 7 yearsThis only works with java.sql.Timestamp, there is no way to make it work with java.util.Date if your json contains number
-
Pierrick about 7 yearsIf you can use java8 you're maybe interested in using
java.time.Instant
class and to use regular jackson datatypes. This way you just need@JsonProperty("timestamp") private Instant timestamp
-
lilalinux about 6 years@Pierrick Please turn this into an answer, so I can upvote ;-)