我将 Spring Boot 与以下 ObjectMapper 一起使用:
@Bean
public ObjectMapper objectMapper()
{
final ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.setDateFormat(new StdDateFormat().withColonInTimeZone(true)); // Makes no difference to output
mapper.findAndRegisterModules();
return mapper;
}
当 OffsetDateTimes 被序列化并在响应中返回时,它们的格式如下:
"2020-02-28T12:28:29.01Z"
"2020-02-28T12:36:21.885Z"
我本来希望最后的时区信息看起来像这样:
"2020-02-28T10:41:25.287+00:00"
我在这里遗漏或做错了什么,或者无论如何我可以将时区信息序列化为
+00:00
格式而不是 885Z
格式?
非常感谢!
以下步骤解决了这个问题(取自https://stackoverflow.com/a/41893238/12177456),也感谢@Ralf Wagner和@deHaar:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.6.5</version>
</dependency>
public class OffsetDateTimeSerializer extends JsonSerializer<OffsetDateTime>
{
private static final DateTimeFormatter ISO_8601_FORMATTER = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ssxxx")
.withZone(ZoneId.of("UTC"));
@Override
public void serialize(OffsetDateTime value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException
{
if (value == null) {
throw new IOException("OffsetDateTime argument is null.");
}
jsonGenerator.writeString(ISO_8601_FORMATTER.format(value));
}
}
@Bean
public ObjectMapper objectMapper()
{
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
objectMapper.registerModule(new JavaTimeModule());
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(OffsetDateTime.class, new OffsetDateTimeSerializer());
objectMapper.registerModule(simpleModule);
return objectMapper;
}
新的 Java 8 Time API 提供了一个
DateTimeFormatter
,您可以在其中将格式结尾设置为一个或多个 x
或 X
。根据 api 描述:
偏移量 X 和 x:根据模式字母的数量格式化偏移量。一个字母仅输出小时,例如“+01”,除非分钟非零,在这种情况下也会输出分钟,例如“+0130”。两个字母输出小时和分钟,不带冒号,例如“+0130”。三个字母输出小时和分钟,带有冒号,例如“+01:30”。四个字母输出小时和分钟以及可选的秒,不带冒号,例如“+013015”。五个字母输出小时和分钟以及可选的秒,带有冒号,例如“+01:30:15”。六个或更多字母将引发 IllegalArgumentException。当要输出的偏移量为零时,模式字母“X”(大写)将输出“Z”,而模式字母“x”(小写)将输出“+00”、“+0000”或“+00” :00'.
因此,在您的情况下,您的格式化字符串应以
xxx
结尾,代表 +1:30
,例如"yyyy-MM-dd'T'HH:mm:ss.SSSxxx"
SSS
始终给出毫秒。
要将其与 Jackson 一起使用
DateTimeFormatter
,您需要定义一个自定义序列化器
public class DefaultZonedDateTimeSerializer extends JsonSerializer<ZonedDateTime> {
private static final DateTimeFormatter ISO_8601_FORMATTER = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
.withZone(ZoneId.of("UTC"));
@Override
public void serialize(ZonedDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (value == null) {
throw new IOException("ZonedDateTime argument is null.");
}
gen.writeString(ISO_8601_FORMATTER.format(value));
}
并用
注释 Bean 中的相应字段@JsonSerialize(using = DefaultZonedDateTimeSerializer.class)
private ZonedDateTime someTimeProperty;
或者您需要从
DateTimeFormatter
转换为 DateFormat
(较旧,但由 Jackson 使用),如下所述:将 DateTimeFormatter 与 ObjectMapper 一起使用
有多种使用预构建格式或向
DateTimeFormatter
提供自定义模式的可能性。
看看这些(非常简单)的例子:
public static void main(String[] arguments) {
Instant now = Instant.now();
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(now, ZoneId.of("UTC"));
OffsetDateTime offsetDateTime = OffsetDateTime.ofInstant(now, ZoneId.of("UTC"));
System.out.println(zonedDateTime.toString());
System.out.println(offsetDateTime.toString());
System.out.println(zonedDateTime.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
System.out.println(offsetDateTime.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
System.out.println(zonedDateTime.format(
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ"))
);
System.out.println(offsetDateTime.format(
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssxxx")
)
);
}
我认为你期待的是最后一个,一种以
xxx
结尾的模式,这会导致偏移量始终以HH:mm
的形式显示,代码示例的输出是:
2020-02-28T12:49:02.388Z[UTC]
2020-02-28T12:49:02.388Z
2020-02-28T12:49:02.388Z[UTC]
2020-02-28T12:49:02.388Z
2020-02-28T12:49:02+0000
2020-02-28T12:49:02+00:00
如果您使用 JodaDateTime,请尝试以下操作:
@Bean
public ObjectMapper getObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JodaModule());
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
return objectMapper;
}
感谢
@Ralf Wagner
的answer,它引用的API描述很有帮助。
我在我的 Spring Boot 项目中这样做了,它工作正常:
spring:
jackson:
zoned-date-time-date-format: "yyyy-MM-dd'T'HH:mm:ssxxx" # This is a custom key
import com.fasterxml.jackson.datatype.jsr310.ser.ZonedDateTimeSerializer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.jackson.JsonComponent;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import java.time.format.DateTimeFormatter;
@SuppressWarnings("unused")
@JsonComponent
public class JacksonConfig implements Jackson2ObjectMapperBuilderCustomizer {
@Value("${spring.jackson.zoned-date-time-date-format:}")
protected String dateFormat;
@Override
public void customize(Jackson2ObjectMapperBuilder builder) {
// If the "spring.jackson.zoned-date-time-date-format" item exists in application.yaml
if (!dateFormat.isBlank()) {
// Configure the date and time format used when serializing Java 8 time API classes
var dateTimeFormatter = DateTimeFormatter.ofPattern(dateFormat);
builder.serializers(new ZonedDateTimeSerializer(dateTimeFormatter));
}
}
}