使用 org.threeten.bp.format.DateTimeFormatter 解析多个模式
Parse multiple patterns using org.threeten.bp.format.DateTimeFormatter
简单版:
我需要能够仅使用一个 org.threeten.bp.format.DateTimeFormatter
对象来解析两种类型的时间戳字符串。
模式 1(“YYYY-MM-DD HH:mm:ss.SSSSSS”——此代码有效):
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("YYYY-MM-DD HH:mm:ss.SSSSSS");
System.out.println(dtf.parse("2020-06-30 20:20:42.871216"));
模式 2(“YYYY-MM-DD'T'HH:mm:ss.SSS'Z'”——此代码也有效):
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("YYYY-MM-DD'T'HH:mm:ss.SSS'Z'");
System.out.println(dtf.parse("2020-06-30T20:20:42.871Z"));
但我需要单个对象来解析两者(这行不通,显然哈哈):
DateTimeFormatter dtf = DateTimeFormatter
.ofPattern("YYYY-MM-DD HH:mm:ss.SSSSSS")
.andThisPattern("YYYY-MM-DD'T'HH:mm:ss.SSS'Z'");
System.out.println(dtf.parse("2020-06-30 20:20:42.871216"));
System.out.println(dtf.parse("2020-06-30T20:20:42.871Z"));
我已经尝试了几件事,这是最新的尝试:
DateTimeFormatterBuilder dtfb = new DateTimeFormatterBuilder();
DateTimeFormatter dtf = dtfb
.appendPattern("YYYY-MM-DD HH:mm:ss.SSSSSS")
.appendPattern("YYYY-MM-DD'T'HH:mm:ss.SSS'Z'")
.toFormatter();
System.out.println(dtf.parse("2020-06-30 20:20:42.871216"));
System.out.println(dtf.parse("2020-06-30T20:20:42.871Z"));
但这没有用。我做的任何事情似乎都不允许单个对象解析两种类型。
有没有办法做到这一点?
更大的上下文(Swagger codegen):
我有一个使用 Java Swagger codegen 与 Web 服务交互的应用程序。来自 Web 服务的 JSON 响应包含两种时间戳格式(见上文)。在我的应用程序的某个时刻,我调用 JSON#deserialize 尝试使用(可配置的)DateTimeFormatter 对象。但是,在您调用之前不可能知道您将拥有哪种时间戳格式。
2020-07-06 18:53:45 ERROR PartyContactMethodsControllerEmail:352 - org.threeten.bp.format.DateTimeParseException: Text '2020-07-06 18:53:45.449445' could not be parsed at index 10
at org.threeten.bp.format.DateTimeFormatter.parseToBuilder(DateTimeFormatter.java:1587)
at org.threeten.bp.format.DateTimeFormatter.parse(DateTimeFormatter.java:1491)
at org.threeten.bp.OffsetDateTime.parse(OffsetDateTime.java:359)
at webservice.com.webapp.invoker.JSON$OffsetDateTimeTypeAdapter.read(JSON.java:183)
at webservice.com.webapp.invoker.JSON$OffsetDateTimeTypeAdapter.read(JSON.java:1)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.read(ReflectiveTypeAdapterFactory.java:129)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.read(ReflectiveTypeAdapterFactory.java:129)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
at com.google.gson.Gson.fromJson(Gson.java:887)
at com.google.gson.Gson.fromJson(Gson.java:852)
at com.google.gson.Gson.fromJson(Gson.java:801)
at webservice.com.webapp.invoker.JSON.deserialize(JSON.java:133)
at webservice.com.webapp.invoker.ApiClient.deserialize(ApiClient.java:711)
at webservice.com.webapp.invoker.ApiClient.handleResponse(ApiClient.java:914)
at webservice.com.webapp.invoker.ApiClient.execute(ApiClient.java:841)
...
因此 desearialize
调用在发现它不期望的时间戳格式时无法成功解析 JSON 响应。
又是原始问题:如何配置 DateTimeFormatter(在调用反序列化之前)不阻塞时间戳格式?有没有一种方法可以配置/连接 Swagger codegen 以适应服务器的响应?
您所问的基本挑战是这两种格式不传达兼容的信息。 2020-06-30 20:20:42.871216
是没有时区或 UTC 偏移量的日期和时间。它可能表示某个时间点,但我们无法正确解释它,除非我们知道哪个时区是正确的。另一方面,2020-06-30T20:20:42.871Z
中的尾随 Z
是零形式 UTC 的偏移量,因此这里我们有提供给我们的信息。
在下面的代码片段中,我假设没有 UTC 偏移量的格式也可以用 UTC 来理解。
DateTimeFormatter singleFormatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendPattern("[ ]['T']")
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.appendPattern("[X]")
.parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
.toFormatter();
OffsetDateTime odt1 = OffsetDateTime.parse("2020-06-30 20:20:42.871216", singleFormatter);
System.out.println(odt1);
OffsetDateTime odt2 = OffsetDateTime.parse("2020-06-30T20:20:42.871Z", singleFormatter);
System.out.println(odt2);
输出为:
2020-06-30T20:20:42.871216Z
2020-06-30T20:20:42.871Z
我通过格式模式字符串中的可选元素处理日期和时间之间的 space 和 T
之间的区别。方括号中的任何内容都被认为是可选的,因此 [ ]['T']
解析可选 space 后跟可选文字 T
。小数位数的变化很容易,因为内置的 DateTimeFormatter.ISO_LOCAL_TIME
可以处理这个问题。这是我想要使用构建器的主要原因:它允许我将其他格式化程序构建到我正在构建的格式化程序中。最后,可选的偏移量通过一组新的方括号处理。大写 X
解析一个偏移量,该偏移量可以作为零给出 Z
。由于 Z
是一个偏移量,因此您绝不能使用硬编码文字 Z
来解析它,因为这会丢弃偏移量信息。解析偏移量允许我将整个字符串解析为 OffsetDateTime
。只有当其他格式没有偏移量时,这怎么可能呢?对 parseDefaulting()
的调用指定了解析 none 时要使用的偏移量。
简单版:
我需要能够仅使用一个 org.threeten.bp.format.DateTimeFormatter
对象来解析两种类型的时间戳字符串。
模式 1(“YYYY-MM-DD HH:mm:ss.SSSSSS”——此代码有效):
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("YYYY-MM-DD HH:mm:ss.SSSSSS");
System.out.println(dtf.parse("2020-06-30 20:20:42.871216"));
模式 2(“YYYY-MM-DD'T'HH:mm:ss.SSS'Z'”——此代码也有效):
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("YYYY-MM-DD'T'HH:mm:ss.SSS'Z'");
System.out.println(dtf.parse("2020-06-30T20:20:42.871Z"));
但我需要单个对象来解析两者(这行不通,显然哈哈):
DateTimeFormatter dtf = DateTimeFormatter
.ofPattern("YYYY-MM-DD HH:mm:ss.SSSSSS")
.andThisPattern("YYYY-MM-DD'T'HH:mm:ss.SSS'Z'");
System.out.println(dtf.parse("2020-06-30 20:20:42.871216"));
System.out.println(dtf.parse("2020-06-30T20:20:42.871Z"));
我已经尝试了几件事,这是最新的尝试:
DateTimeFormatterBuilder dtfb = new DateTimeFormatterBuilder();
DateTimeFormatter dtf = dtfb
.appendPattern("YYYY-MM-DD HH:mm:ss.SSSSSS")
.appendPattern("YYYY-MM-DD'T'HH:mm:ss.SSS'Z'")
.toFormatter();
System.out.println(dtf.parse("2020-06-30 20:20:42.871216"));
System.out.println(dtf.parse("2020-06-30T20:20:42.871Z"));
但这没有用。我做的任何事情似乎都不允许单个对象解析两种类型。
有没有办法做到这一点?
更大的上下文(Swagger codegen):
我有一个使用 Java Swagger codegen 与 Web 服务交互的应用程序。来自 Web 服务的 JSON 响应包含两种时间戳格式(见上文)。在我的应用程序的某个时刻,我调用 JSON#deserialize 尝试使用(可配置的)DateTimeFormatter 对象。但是,在您调用之前不可能知道您将拥有哪种时间戳格式。
2020-07-06 18:53:45 ERROR PartyContactMethodsControllerEmail:352 - org.threeten.bp.format.DateTimeParseException: Text '2020-07-06 18:53:45.449445' could not be parsed at index 10
at org.threeten.bp.format.DateTimeFormatter.parseToBuilder(DateTimeFormatter.java:1587)
at org.threeten.bp.format.DateTimeFormatter.parse(DateTimeFormatter.java:1491)
at org.threeten.bp.OffsetDateTime.parse(OffsetDateTime.java:359)
at webservice.com.webapp.invoker.JSON$OffsetDateTimeTypeAdapter.read(JSON.java:183)
at webservice.com.webapp.invoker.JSON$OffsetDateTimeTypeAdapter.read(JSON.java:1)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.read(ReflectiveTypeAdapterFactory.java:129)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.read(ReflectiveTypeAdapterFactory.java:129)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
at com.google.gson.Gson.fromJson(Gson.java:887)
at com.google.gson.Gson.fromJson(Gson.java:852)
at com.google.gson.Gson.fromJson(Gson.java:801)
at webservice.com.webapp.invoker.JSON.deserialize(JSON.java:133)
at webservice.com.webapp.invoker.ApiClient.deserialize(ApiClient.java:711)
at webservice.com.webapp.invoker.ApiClient.handleResponse(ApiClient.java:914)
at webservice.com.webapp.invoker.ApiClient.execute(ApiClient.java:841)
...
因此 desearialize
调用在发现它不期望的时间戳格式时无法成功解析 JSON 响应。
又是原始问题:如何配置 DateTimeFormatter(在调用反序列化之前)不阻塞时间戳格式?有没有一种方法可以配置/连接 Swagger codegen 以适应服务器的响应?
您所问的基本挑战是这两种格式不传达兼容的信息。 2020-06-30 20:20:42.871216
是没有时区或 UTC 偏移量的日期和时间。它可能表示某个时间点,但我们无法正确解释它,除非我们知道哪个时区是正确的。另一方面,2020-06-30T20:20:42.871Z
中的尾随 Z
是零形式 UTC 的偏移量,因此这里我们有提供给我们的信息。
在下面的代码片段中,我假设没有 UTC 偏移量的格式也可以用 UTC 来理解。
DateTimeFormatter singleFormatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendPattern("[ ]['T']")
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.appendPattern("[X]")
.parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
.toFormatter();
OffsetDateTime odt1 = OffsetDateTime.parse("2020-06-30 20:20:42.871216", singleFormatter);
System.out.println(odt1);
OffsetDateTime odt2 = OffsetDateTime.parse("2020-06-30T20:20:42.871Z", singleFormatter);
System.out.println(odt2);
输出为:
2020-06-30T20:20:42.871216Z 2020-06-30T20:20:42.871Z
我通过格式模式字符串中的可选元素处理日期和时间之间的 space 和 T
之间的区别。方括号中的任何内容都被认为是可选的,因此 [ ]['T']
解析可选 space 后跟可选文字 T
。小数位数的变化很容易,因为内置的 DateTimeFormatter.ISO_LOCAL_TIME
可以处理这个问题。这是我想要使用构建器的主要原因:它允许我将其他格式化程序构建到我正在构建的格式化程序中。最后,可选的偏移量通过一组新的方括号处理。大写 X
解析一个偏移量,该偏移量可以作为零给出 Z
。由于 Z
是一个偏移量,因此您绝不能使用硬编码文字 Z
来解析它,因为这会丢弃偏移量信息。解析偏移量允许我将整个字符串解析为 OffsetDateTime
。只有当其他格式没有偏移量时,这怎么可能呢?对 parseDefaulting()
的调用指定了解析 none 时要使用的偏移量。