Jackson OffsetDateTime 序列化 Z 而不是 +00:00 时区?

Ror*_*ory 9 java json date jackson

我将 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;
}
Run Code Online (Sandbox Code Playgroud)

当 OffsetDateTimes 被序列化并在响应中返回时,它们的格式如下:

"2020-02-28T12:28:29.01Z"
"2020-02-28T12:36:21.885Z"

Run Code Online (Sandbox Code Playgroud)

我本来希望最后的时区信息看起来像这样:

"2020-02-28T10:41:25.287+00:00"
Run Code Online (Sandbox Code Playgroud)

我在这里遗漏或做错了什么,或者无论如何我可以将时区信息序列化为格式+00:00而不是885Z格式?

非常感谢!

Ror*_*ory 11

以下步骤解决了这个问题(取自/sf/answers/2932526691/),也感谢@Ralf Wagner和@deHaar:

<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-jsr310</artifactId>
  <version>2.6.5</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)
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));
    }
}
Run Code Online (Sandbox Code Playgroud)
@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;
}
Run Code Online (Sandbox Code Playgroud)


Ral*_*ner 7

新的 Java 8 时间 API 提供了一个DateTimeFormatter可以将格式结尾设置为一个或多个xX. 根据api描述:

偏移量 X 和 x:这根据模式字母的数量格式化偏移量。一个字母仅输出小时,例如“+01”,除非分钟非零,在这种情况下也会输出分钟,例如“+0130”。两个字母输出小时和分钟,不带冒号,例如“+0130”。三个字母输出小时和分钟,带有冒号,例如“+01:30”。四个字母输出小时和分钟以及可选的秒,不带冒号,例如“+013015”。五个字母输出小时和分钟以及可选的秒,带有冒号,例如“+01:30:15”。六个或更多字母将引发 IllegalArgumentException。当要输出的偏移量为零时,模式字母“X”(大写)将输出“Z”,而模式字母“x”(小写)将输出“+00”、“+0000”或“+00” :00'。

因此,在您的情况下,您的格式化字符串应以xxxfor结尾+1:30,例如"yyyy-MM-dd'T'HH:mm:ss.SSSxxx"始终SSS给出毫秒。

DateTimeFormatter与 Jackson 一起使用,您需要定义一个自定义序列化器

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));
}
Run Code Online (Sandbox Code Playgroud)

并在 beans 中注释相应的字段

@JsonSerialize(using = DefaultZonedDateTimeSerializer.class)
private ZonedDateTime someTimeProperty;
Run Code Online (Sandbox Code Playgroud)

或者您需要从 转换为DateTimeFormatterDateFormat较旧,但由 Jackson 使用),如下所述:Using DateTimeFormatter with ObjectMapper


deH*_*aar 6

使用预构建格式或向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")
        )
    );
}
Run Code Online (Sandbox Code Playgroud)

我认为您期望的是最后一个,以 结尾的模式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
Run Code Online (Sandbox Code Playgroud)