【问题标题】:Correct java.time representation of XMLGregorianCalendarXMLGregorianCalendar 的正确 java.time 表示
【发布时间】:2022-07-24 23:27:45
【问题描述】:

我有一个包含以下内容的 XML 元素:

<lastModified>2019-10-09T19:20:45.677+02:00</lastModified>

这映射到 Java 的 XMLGregorianCalendar

我需要将此值转换为适当的 java.time 实例。

我对哪个 java.time 类是这个 XMLGregorianCalendar 值的“正确”(即无损)表示有点困惑。

我想应该是ZonedDateTime 还是OffsetDateTime 更好的选择?

【问题讨论】:

  • 这取决于很多。 ZonedDateTime 是一个选项,但由于 XMLGregorianCalendar 所谓的 timezone 不仅仅是 UTC 偏移量,我更倾向于OffsetDateTime。但是,XMLGreforianCalendar 中的任何字段都可能未定义,因此取决于在某些情况下的具体使用 LocalDateLocalDateTime 或任何 java.time 日期或时间类可能是合适的。
  • 好吧,事实证明你必须使用OffsetDateTime,因为你的String 2019-10-09T19:20:45.677+02:00 不包含一个区域,而是一个偏移量(几个区域可能有一个偏移量)。

标签: java java-time xmlgregoriancalendar


【解决方案1】:

您拥有的String ("2019-10-09T19:20:45.677+02:00") 是 ISO 格式,甚至不需要额外的格式化程序来解析它。使用 OffsetDateTime 的主要原因是最后 6 个字符:+02:00,表示与 UTC 的偏移量为 2 小时(实际上可能不止一个时区同时具有此偏移量)。

您可以像这样将此值转换为 正确的 java.time 实例,例如:

public static void main(String[] args) throws DatatypeConfigurationException {
    // your example datetime
    String lastModified = "2019-10-09T19:20:45.677+02:00";
    // create an XMLGregorianCalendar for example purpose
    XMLGregorianCalendar xmlGC = DatatypeFactory.newInstance()
                                                .newXMLGregorianCalendar(lastModified);
    // print it once in order to see the values
    System.out.println("XMLGregorianCalendar: " + xmlGC.toString());
    // parse its toString() method to an OffsetDateTime
    OffsetDateTime lastModOdt = OffsetDateTime.parse(xmlGC.toString());
    // format the content of the OffsetDateTime in ISO standard
    System.out.println("OffsetDateTime:       " 
            + lastModOdt.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
}

输出:

XMLGregorianCalendar: 2019-10-09T19:20:45.677+02:00
OffsetDateTime:       2019-10-09T19:20:45.677+02:00

这应该是正确的(不丢失任何信息就足够无损)。

【讨论】:

  • 感谢您的回答,但我需要使用 XMLGregorianCalendar 实例而不是字符串表示形式。
  • @Abid OK,看我的编辑,你基本上可以解析XMLGregorianCalendartoString()方法…
  • 是的,此时有许多时区共享偏移量 +02:00。仅举几个例子:Africa/Mbabane、Europe/Zagreb、Europe/Madrid、Africa/Bujumbura、Antarctica/Troll、Arctic/Longyearbyen 和 Europe/Kaliningrad。
【解决方案2】:

我整个早上都在为类似的问题苦苦挣扎,而 Ole 的 cmets 比公认的答案更有洞察力,所以我想我应该发布我得出的结论。

技术上是的,与 XMLGregorianCalendar 完全等效的是 OffsetDateTime (假设您的示例,其中填充了 y-m-d h:m:s+z 字段),因为时区偏移量是已知的,但它是未知的实际时区(如对于其他 cmets,有许多时区都偏移 +2:00)。您可以像这样轻松转换它,而无需通过中间字符串:

xmlGC.toGregorianCalendar ().toZonedDateTime ().toOffsetDateTime ()

但我认为真正的答案是 这取决于你想用它做什么。就我而言,我想向用户显示日期/时间。如果这是真的,你真的关心日期/时间碰巧存储在 XML 中的哪个时区吗?以下两者实际上是相同的,即它们都代表相同的时间点。

<lastModified>2019-10-09T19:20:45.677+02:00</lastModified>
<lastModified>2019-10-09T20:20:45.677+01:00</lastModified>

如果您不关心 XML 中的时区,而只关心它所代表的时间点,那么正确的答案是 Instant,您可以像这样

xmlGC.toGregorianCalendar ().toInstant ()

然后从那里应用用户所在的任何时区,而不是 XML 中的时区。所以对我来说正确的答案是:

xmlGC.toGregorianCalendar ().toInstant ().atZone (ZoneId.systemDefault ())

【讨论】:

    猜你喜欢
    • 2023-04-02
    • 2011-12-31
    • 1970-01-01
    • 2019-09-02
    • 1970-01-01
    • 2020-06-01
    • 2014-08-18
    • 2013-04-28
    • 1970-01-01
    相关资源
    最近更新 更多