这似乎是SimpleDateFormat(杰克逊内部使用)的问题,如stated in this answer。我也用纯Java(没有Jackson)做了一个测试,错误也发生了:
String s = "2017-09-21T11:25:32.1Z";
Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SX").parse(s);
System.out.println(new Timestamp(date.getTime())); // 2017-09-21 08:25:32.001
如果您可以更改 xml,则向输入 (2017-09-21T11:25:32.100Z) 添加零即可。
另一种选择是为您的字段编写自定义反序列化程序(使用Timestamp 类中的正确方法从Instant 转换):
public class CustomTimestampDeserializer extends JsonDeserializer<Timestamp> {
@Override
public Timestamp deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
return Timestamp.from(Instant.parse(p.getText()));
}
}
然后您注释该字段以使用此自定义反序列化器:
@JacksonXmlProperty(localName = "ts")
@JsonDeserialize(using = CustomTimestampDeserializer.class)
Timestamp ts;
现在,当打印 Timestamp 时,您会得到正确的值:
2017-09-21 08:25:32.1
等一下,为什么小时是08? - 那是因为当你System.out.println 和Timestamp 时,它隐式调用了toString() 方法,而这个方法将@ 987654338@ 到 JVM 默认时区(在我的情况下,它是 America/Sao_Paulo,所以它是正确的,因为圣保罗的 08:25 AM 相当于 UTC 的 11:25 AM)。但是Timestamp保存的值是正确的。
您可以在this article 中阅读更多关于toString() 行为的信息——它谈到了java.util.Date,但想法是一样的(特别是因为Timestamp 扩展了Date,所以它有同样的问题)。
要将其序列化回 xml,您还可以配置自定义序列化程序:
public class CustomTimestampSerializer extends JsonSerializer<Timestamp> {
@Override
public void serialize(Timestamp value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
gen.writeString(value.toInstant().toString());
}
}
然后你注释字段以使用这个序列化器:
@JacksonXmlProperty(localName = "ts")
@JsonDeserialize(using = CustomTimestampDeserializer.class)
@JsonSerialize(using = CustomTimestampSerializer.class)
Timestamp ts;
只是一个细节:Instant.toString() 将导致2017-09-21T11:25:32.100Z。如果您最后不想要那些额外的零,您可以使用DateTimeFormatter 自定义格式。所以自定义的序列化器会是这样的:
public class CustomTimestampSerializer extends JsonSerializer<Timestamp> {
private DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// date/time
.appendPattern("yyyy-MM-dd'T'HH:mm:ss")
// nanoseconds without leading zeroes (from 0 to 9 digits)
.appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true)
// offset (Z)
.appendOffsetId()
// create formatter (set zone to UTC to properly format the Instant)
.toFormatter().withZone(ZoneOffset.UTC);
@Override
public void serialize(Timestamp value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
gen.writeString(fmt.format(value.toInstant()));
}
}
这会将时间戳打印为2017-09-21T11:25:32.1Z。