你必须告诉Jackson日期的格式。基本上,你有 年-月-日
接着是 时:分:秒.毫秒
和2位数字的偏移量 (+02
)。所以你的模式将会是:
year-month-day hour:minute:second.microseconds+02
@JsonProperty("timestamp")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSSSSSx")
private OffsetDateTime timestamp
查看所有日期/时间模式以获得更详细的解释。
如果要在OffsetDateTime
中保留相同的偏移量(+02
),请不要忘记将DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE
选项调整为false
。
如果设置为true
(在我的测试中),结果将转换为UTC(但实际上会转换为Jackson配置的任何时区):
2017-09-17T11:45:42.710576Z
如果我设置为false
,则输入中使用的偏移量将被保留:
2017-09-17T13:45:42.710576+02:00
上面的代码对于小数点后正好有6位数字的情况可以工作。但是如果这个数量变化了,您可以使用用方括号[]
分隔的可选模式。
例如:如果输入可能有6个或3个小数位,则可以使用pattern="yyyy-MM-dd HH:mm:ss.[SSSSSS][SSS]x"
。可选部分[SSSSSS]
和[SSS]
告诉解析器要么考虑6位数字,要么考虑3位数字。
可选模式的问题在于,在序列化时,它会打印所有模式(因此它将两次打印秒的小数部分:一次是6个数字,一次是3个数字)。
另一种选择是创建自定义的序列化程序和反序列化程序(通过扩展com.fasterxml.jackson.databind.JsonSerializer
和com.fasterxml.jackson.databind.JsonDeserializer
):
public class CustomDeserializer extends JsonDeserializer<OffsetDateTime> {
private DateTimeFormatter formatter;
public CustomDeserializer(DateTimeFormatter formatter) {
this.formatter = formatter;
}
@Override
public OffsetDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException {
return OffsetDateTime.parse(parser.getText(), this.formatter);
}
}
public class CustomSerializer extends JsonSerializer<OffsetDateTime> {
private DateTimeFormatter formatter;
public CustomSerializer(DateTimeFormatter formatter) {
this.formatter = formatter;
}
@Override
public void serialize(OffsetDateTime value, JsonGenerator gen, SerializerProvider provider) throws IOException, JsonProcessingException {
gen.writeString(value.format(this.formatter));
}
}
然后您可以在JavaTimeModule
中注册它们。 如何配置取决于您使用的环境(例如:在Spring中,您可以在xml文件中进行配置)。 我将以编程方式作为示例进行操作。
首先,我使用java.time.format.DateTimeFormatterBuilder
创建格式化程序:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd HH:mm:ss")
.optionalStart().appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true).optionalEnd()
.appendPattern("x")
.toFormatter();
这个格式化程序可以接受0到9位小数秒的可选部分。然后我使用上面的自定义类并在 ObjectMapper
中注册它们:
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false);
JavaTimeModule module = new JavaTimeModule();
module.addSerializer(OffsetDateTime.class, new CustomSerializer(formatter));
module.addDeserializer(OffsetDateTime.class, new CustomDeserializer(formatter));
mapper.registerModule(module);
我还从字段中删除了@JsonFormat
注释:
@JsonProperty("timestamp")
private OffsetDateTime timestamp
现在它接受像2017-09-17 13:45:42+02
(无秒的小数)和2017-09-17 13:45:42.71014+02
(5位小数)这样的值。它可以解析从0到9位小数(API支持的最大值为9),并且在序列化时打印完全相同的数量。
上述替代方案非常灵活,因为它允许在自定义类中设置格式化程序。但它也针对所有OffsetDateTime
字段设置了序列化和反序列化。
如果您不想这样做,也可以创建一个具有固定格式化程序的类:
static class CustomDeserializer extends JsonDeserializer<OffsetDateTime> {
private DateTimeFormatter formatter =
}
static class CustomSerializer extends JsonSerializer<OffsetDateTime> {
private DateTimeFormatter formatter =
}
然后,您可以使用注释com.fasterxml.jackson.databind.annotation.JsonSerialize
和com.fasterxml.jackson.databind.annotation.JsonDeserialize
仅将这些添加到您想要的字段中:
@JsonProperty("timestamp")
@JsonSerialize(using = CustomSerializer.class)
@JsonDeserialize(using = CustomDeserializer.class)
private OffsetDateTime timestamp;
有了这个,您就不需要在模块中注册自定义序列化程序,只有被注释的字段将使用自定义类(其他OffsetDateTime
字段将使用默认设置)。
OffsetDateTime
还是ZonedDateTime
? - Kwers Thttps://dev59.com/1V0a5IYBdhLWcg3woZ83
中那样做,但我不知道它在字符串上应该是什么样子。 - Kwers Tyyyy-MM-dd HH:mm:ss.[SSS][SSSSSS]x
- 方括号分隔符是可选的模式,因此它接受3或6个数字。我不确定6位数字模式是否应该放在前面(有时顺序很重要)。抱歉,我刚离开家,无法进行适当的测试。 - user7605325yyyy-MM-dd HH:mm:ss.[SSSSSS][SSS]x
。我已经更新了答案。 - user7605325