json Jackson将ISO 8601格式的日期时间转换为Java8 Instant

xriantvc  于 2023-10-21  发布在  Java
关注(0)|答案(6)|浏览(110)

我正在尝试使用Jackson将ISO 8601格式的日期转换为Java8 java.time.Instant。我用ObjectMapper注册了JavaTimeModule,并关闭了WRITE_DATES_AS_TIMESTAMPS设置。
但是,如果尝试对2016-03-28T19:00:00.000+01:00进行格式化,它将不起作用,因为JavaTimeModule似乎只会对UTC时区偏移格式的日期时间进行格式化(例如,2016-03-28T18:00:00.000Z)。然后我尝试使用@JsonFormat注解如下:

@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone = "UTC")

就像这样:

@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone = JsonFormat.DEFAULT_TIMEZONE)

然而,这两种方法都不起作用,我得到了一个例外:

com.fasterxml.jackson.databind.JsonMappingException: Unsupported field: YearOfEra (through reference chain: org.example.Article["date"])

这意味着timezone参数被忽略,并且日期时间格式化程序不知道如何格式化没有时区的Instant。
有没有一种方法可以使用Jackson和JavaTimeModule将不在UTC时区偏移中的ISO 8601字符串转换为Java 8 java.time.Instant,而无需编写自定义转换器?

tyu7yeag

tyu7yeag1#

你需要在modell类中通过XXX设置显式时区:

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX")

(see:https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html

bvpmtnay

bvpmtnay2#

如果你想将Date对象序列化为ISO-8601,你根本不需要指定模式- ISO-8601是默认模式。在JsonFormat Java doc中提到:
常见的用法包括在替代表示之间进行选择-例如,Date是否被序列化为数字(Java时间戳)或String(例如ISO-8601兼容的时间值)-以及使用pattern()属性配置确切的细节。
[emphasasis mine]你应该从上面的文字中理解,指定shape = STRING意味着ISO-8601格式,但你可以使用pattern属性选择其他东西。
根据我的经验,这总是会产生UTC日期格式(时区呈现为+0000),这可能是我的VM中的默认时区(即使我的操作系统时钟没有设置为UTC)。

aurhwmvo

aurhwmvo3#

在Jackson2.9.8(目前的一个,因为我写这篇文章),最好使用即时而不是日期。
你需要添加一个依赖项:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.9.8</version>
</dependency>

另外,注册模块并将SerializationFeature.WRITE_DATES_AS_TIMESTAMPS配置为false。

new ObjectMapper()
                .findAndRegisterModules()
                .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

有关Jacksonfor Java 8的更多信息,请访问:https://github.com/FasterXML/jackson-modules-java8

iqih9akk

iqih9akk4#

Jackson可以全局配置(不带注解)以接受带或不带冒号的时间戳:

ObjectMapper mapper = new ObjectMapper();
mapper.setDateFormat(new StdDateFormat().withColonInTimeZone(true));

自2.11版以来,默认的Jackson时区格式已从“+0000”更改为“+00:00”。这两种格式都符合ISO-8601标准。

omjgkv6w

omjgkv6w5#

格式“Z”不适用于“+01:00”,因为这是一种不同的模式。JsonFormat使用SimpleDateFormat模式。* * 大写**中的“Z”仅代表严格的RFC 822。你必须使用这样的语法:“+0100”,不带冒号。
参见:ISO 8601:2004SimpleDateFormat patterns

dwbf0jvd

dwbf0jvd6#

我在RMQ队列上发送Instant数据类型变量时遇到了这个问题。它在不同的场景下会出错。
我遇到的第一个错误是
java.base/java.lang.Thread.run(Thread.java:829)\n原因:com.fasterxml.Jackson.databind.exc.InvalidDefinitionException:默认情况下不支持Java 8日期/时间类型java.time.Instant
解决方案过于依赖

<dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
    </dependency>

然后我开始面临的第二个问题是它不能序列化日期格式。我试着用对象Map器加载JAVA时间模块,但这对我没有帮助。对我有效的方法如下。

@JsonSerialize(using = InstantSerializer.class)
@JsonDeserialize(using = CustomInstantDeserializer.class)
Instant updateTime;

我不得不写,因为它给出了InvalidExceptionException的错误:类com.fasterxml.jackson.datatype.jsr310.deser.InstantObjectAliizer没有默认(无参数)构造函数\n

public class CustomInstantDeserializer extends 
 InstantDeserializer<Instant> { 
      public CustomInstantDeserializer() {
           super(InstantDeserializer.INSTANT,
            new DateTimeFormatterBuilder().
     parseCaseInsensitive()
   .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
                    .optionalStart().appendOffset("+HH:MM", 
  "+00:00").optionalEnd().optionalStart()
                    .appendOffset("+HHMM", 
    "+0000").optionalEnd().optionalStart().appendOffset("+HH", "Z")
                    .optionalEnd().toFormatter());
      }

    }

相关问题