当前位置: 首页 > 知识库问答 >
问题:

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

钦良弼
2023-03-14

我将Spring Boot与以下对象映射器一起使用:

@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 格式?

非常感谢!

共有3个答案

上官锦
2023-03-14

有几种可能性可以使用预构建的格式或为DateTimeFor的提供自定义模式

看看这些(非常简单的)例子:

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
燕扬
2023-03-14

新的Java8 Time API提供了一个DateTimeForith,您可以在其中将格式的末尾设置为一个或多个xX。根据api描述:

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

因此,在您的情况下,对于1:30,您的格式化字符串应该以xxx结尾,例如"yyyy-MM-dd'T'HH: mm:ss.SSSxxx"SSS总是给出毫秒数。

要将这个< code>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));
}

并用

@JsonSerialize(using = DefaultZonedDateTimeSerializer.class)
private ZonedDateTime someTimeProperty;

或者您需要从 DateTimeFormatter 转换为 DateFormat(较旧,但由 Jackson 使用),如下所述:将 DateTimeFormatter 与 ObjectMapper 一起使用

勾渝
2023-03-14

以下步骤解决了此问题(取自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;
}
 类似资料:
  • 问题内容: 我最近接手了一个十年前创建的旧项目。它使用MySQL 5.1。 除其他外,我需要将默认字符集从latin1更改为utf8。 例如,我有这样的表: 我设置了自己的Mac来进行此工作。不用考虑太多,我运行了“ brew install mysql”,它安装了MySQL 5.7。所以我有一些版本冲突。 我下载了此数据库的副本并将其导入。 如果我尝试运行这样的查询: 我收到此错误: 我以为可以

  • 问题内容: 我有一个包含日期的数据库表 我正在使用MySQL。有时从程序中将没有日期的数据传递到数据库。因此, 当使用带错误的日期列调用表数据时,日期值会自动分配给它 在插入数据时,我尝试将null值传递给日期,但是将其分配给当前时间。 有什么办法可以在不更改表结构的情况下获得? 问题答案: 您可以在数据源配置中直接使用此JDBC URL: jdbc:mysql://您的服务器:3306 /您的数

  • 问题内容: 我在用Java重置小时数时遇到问题。对于给定的日期,我要将小时设置为00:00:00。 这是我的代码: 问题是,有时时间是,有时是时间,当我查询数据库中保存的实体以及查询的实际实体时间(存储的实际时间)失败时。 我知道! 我正在使用AppEngine。这是Appengine错误,问题还是其他问题?还是取决于其他因素? 问题答案: 使用另一个常数代替,使用。 使用0-11(与AM / P

  • 问题内容: 字段定义 二传手 有谁知道如何将“零日期”转换为适当的值?因为我有错误: 即使我像这样设置“默认”字段和设置器: 我仍然会有同样的问题。 问题答案: 在这里,我将大胆猜测您正在使用MySQL :-)它使用“零日期”作为特殊占位符 -不幸的是,JDBC默认情况下无法处理它们。 解决方案是将“ zeroDateTimeBehavior = convertToNull”指定为MySQL连接的

  • 问题内容: 字段定义 二传手 有谁知道如何将“零日期”转换为适当的值?因为我有错误: 即使我像这样设置“默认”字段和设置器: 我仍然会有同样的问题。 问题答案: 在这里,我将做出一个疯狂的猜测,即您正在使用MySQL :-)它使用“零日期”作为特殊的占位符 -不幸的是,默认情况下JDBC无法处理它们。 解决方案是将“ zeroDateTimeBehavior = convertToNull”指定为

  • 我想在MySQL中允许零日期。我已将更改为。 我已经在中更改了它。 然而,当我尝试插入数据时,我得到了错误, 数据截断:不正确的datetime值:“0000-00-00 00:00:00” MySQL版本为5.7.18。 这方面的任何想法都将大有帮助。