DateTimeFormatter.ISO_OFFSET_DATE_TIME 未按预期工作

DateTimeFormatter.ISO_OFFSET_DATE_TIME not working as expected

基于此 Java 日期时间 - OffsetDateTime.format() Examples article and this official documentation for DateTimeFormatter 我希望我的 OffsetDateTime 被序列化为 2011-12-03T10:15:30+00:00 其中偏移量自其 UTC 以来为 +00:00

我无法设法让 OffsetDateTime 以偏移量呈现,它总是只以 'Z' Zulu 呈现。我做错了什么?

这是 Spring Boot 2.0.0.RELEASE,正如您在屏幕截图中看到的,我在 class 路径上有以下模块并已在 objectMapper 中注册,尽管我认为这不是相对的因为这个问题似乎直接与 DateTimeFormatter 有关,所以我的对象映射器只是使用我提供的格式化程序。

它确实有影响,因为正如您在第二个屏幕截图中看到的那样,当我指定 BASIC_ISO_FORMAT 时它确实会产生不同的结果。

我确实在我的 application.properties 中设置了 属性 设置 spring.jackson.date-format= com.fasterxml.jackson.databind.util.ISO8601DateFormat 但据我了解,这对 OffsetDateTime 没有影响,它只支持以前版本的遗留 Date 对象java。顺便改变一下这个似乎没有像预期的那样影响。

如有任何帮助,我们将不胜感激。

使用 ISO_ZONED_DATE_TIME 格式...

使用 BASIC_ISO_FORMAT... 这确实有影响所以我知道格式化程序正在做一些事情,我只是不清楚为什么 ISO_ZONED_DATE_TIME 没有按预期呈现。

 this.objectMapper = objectMapperBuilder.build()      
      .setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE)
      .disable(SerializationFeature.INDENT_OUTPUT)
      .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
      .disable(SerializationFeature.WRITE_DATES_WITH_ZONE_ID);

 SimpleModule simpleModule = new SimpleModule();
 simpleModule.addSerializer(OffsetDateTime.class, new JsonSerializer<OffsetDateTime>() {
        @Override
        public void serialize(OffsetDateTime offsetDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            String formattedDate = DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(offsetDateTime);
            jsonGenerator.writeString(formattedDate);
        }
    });
this.objectMapper.registerModule(simpleModule);

OffsetDateTime now = OffsetDateTime.now();
TimeZone defaultTimeZone = TimeZone.getDefault();
ZoneId defautlZoneOffset = ZoneOffset.systemDefault();
String serializedOffsetDateTime = this.objectMapper.writeValueAsString(now);
//returns -> "2018-06-27T11:45:56.035Z"

功能,不是错误

DateTimeFormatter. ISO_OFFSET_DATE_TIME 的文档告诉您在使用零偏移量(UTC 本身)时期望 Z 而不是 +00:00

那个文件说:

The format consists of:

• The ISO_LOCAL_DATE_TIME

• The offset ID.

针对第二个项目 link,offset ID。该页面显示:

There are three formats:

• Z - for UTC (ISO-8601)

• +hh:mm or -hh:mm - if the seconds are zero (ISO-8601)

• +hh:mm:ss or -hh:mm:ss - if the seconds are non-zero (not ISO-8601)

ZISO 8601 标准的一部分。任何像样的日期时间库都应该能够解析带有 Z.

的字符串

如果您坚持使用 +00:00 而不是更常见的 Z,您将需要指定自定义格式模式,如 Ole linked 中所述V.V.

没有-00:00

offset is -00:00 since its UTC.

您在问题中对 -00:00 的使用不正确。 ISO 8601 标准明确禁止这样的值。 UTC 本身的偏移量是正零,而不是负零:+00:00.

RFC 3339 自称是 ISO 8601 的“配置文件”。RFC 违反了 ISO 8601,允许使用 -00:00,并赋予它未知偏移量的含义.一个非常糟糕和不明智的选择,恕我直言,令人困惑且不需要。 ISO 8601 已经说明了一个未知的偏移量:只需完全省略偏移量符号即可。

我建议避免这种负零做法和 RFC 3339。

如您所知,将偏移量零(或 Zulu)格式化为 Z 应该可行。它是您使用的标准格式 ISO 8601 的一部分。但是,如果不是:

    static DateTimeFormatter formatter
            = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssxxx");

    @Override
    public void serialize(OffsetDateTime offsetDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        String formattedDate = formatter.format(offsetDateTime);
        jsonGenerator.writeString(formattedDate);
    }

这会将 OffsetDateTime 序列化为例如 2011-12-03T10:14:30+00:00(这在标准中也是允许的)。格式模式字符串中的小写 x 格式化偏移量,而无需使用 Z 作为偏移量零。

以上是格式化程序的简短声明。因为我喜欢尽可能依赖更高级别的标准元素,所以我会考虑更长的变体:

    static DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
            .appendPattern("xxx")
            .toFormatter();

这重用了标准库中的 ISO_LOCAL_DATE_TIME。如果你的时间没有几分之一秒,输出将是相同的。如果有,它将包含在后一种情况下的序列化中,就像 ISO_OFFSET_DATE_TIME 一样,例如 2011-12-03T10:14:30.1234+00:00.

LInk: Wikipedia article: ISO 8601