Java XMLGregorianCalendar 格式 yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z' 的字符串日期

Java String date to XMLGregorianCalendar whit format yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'

我有一个带有日期标签的 soap 网络服务,格式如下

2019-12-01T04:00:00.0000000Z(七个零)

现在我正在实施客户端,我无法创建具有七个零的 XMLGregorianCalendar,我只剩下三个零

我的代码

    DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'");
    Date date = df.parse("2019-12-01T04:00:00.0000000Z");       
    GregorianCalendar gcal = new GregorianCalendar();
    gcal.setTime(date);
    gcal.setTimeZone(TimeZone.getTimeZone("UTC"));

    XMLGregorianCalendar fecha = DatatypeFactory.newInstance().newXMLGregorianCalendar(gcal);

    System.out.println("fecha ->"+fecha.toString());

产出

    fecha ->2019-12-01T07:00:00.000Z

如何让 XMLGregorianCalendar 在格式中保留七个零?

您可以使用接受数据类型的词法表示的工厂方法:

XMLGregorianCalendar fecha = DatatypeFactory.newInstance().newXMLGregorianCalendar(df.format(date));

你可能不需要 7 位小数

通常,SOAP 网络服务不需要任何特定的秒数小数位数。它需要 XML 以及 XML 格式的日期和时间。 XML 的日期和时间格式的灵感来自 ISO 8601 格式(底部的链接)。 日期和时间数据类型 上的 W3Schools 页面甚至没有提到指定秒的任何小数部分的可能性:

The dateTime is specified in the following form "YYYY-MM-DDThh:mm:ss" …

不过,允许使用小数秒,“达到任意精度”以引用 W3C 的 XML 架构第 2 部分:数据类型第二版。因此,如果您的 Web 服务坚持恰好保留 7 位小数,这是一个特殊且不寻常的限制。你可能想挑战一下。

XMLGregorianCalendar

的替代方法

XMLGregorianCalendar class 已经老了。它完全用于为 XML 文档生成 ISO 8601 格式,与 SOAP 和许多其他地方一样。 java.time 的 classes,现代 Java 日期和时间 API,也产生 ISO 8601 格式。我们更喜欢使用这些(除非非常特殊的要求需要 XMLGregorianCalendar)。

    OffsetDateTime odt = OffsetDateTime.of(2019, 12, 1, 4, 0, 0, 0, ZoneOffset.UTC);
    System.out.println(odt);

此代码段输出:

2019-12-01T04:00Z

如果您需要 7 位小数,请使用格式化程序:

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSSSSSX");
    System.out.println(odt.format(formatter));

2019-12-01T04:00:00.0000000Z

当然,如果你已经得到你的字符串,2019-12-01T04:00:00.0000000Z,就像你的问题一样,直接把它放到你的XML文件中。如果您需要先验证它,将它传递给 Instant.parse() 并查看是否得到 DateTimeFormatException.

如果您真的无法避免 XMLGregorianCalendar 秒数为 7 位小数的需要,有两种方法可以生成一个:

  1. DatatypeFactory.newXMLGregorianCalendar​(String) 在另一个答案中使用:

        XMLGregorianCalendar fecha = DatatypeFactory.newInstance()
                .newXMLGregorianCalendar("2019-12-01T04:00:00.0000000Z");
        System.out.println(fecha);
    

    2019-12-01T04:00:00.0000000Z

  2. 正在将 BigDecimal 传递给 DatatypeFactory:

        XMLGregorianCalendar fecha = DatatypeFactory.newInstance()
                .newXMLGregorianCalendar(BigInteger.valueOf(2019), 12, 1, 
                        4, 0, 0, new BigDecimal("0.0000000"), 0);
    

无论如何,在任何情况下我都建议你不要使用SimpleDateFormatDate。那些 classes 设计不佳且早已过时,尤其是前者是出了名的麻烦。 GregorianCalendar也是如此。我们有时可能会将它与 XMLGregorianCalendar 一起使用,因为两者之间存在转换(如您的问题中所用)。 GregorianCalendar只有毫秒精度,所以你永远不会通过这样的转换得到 7 位小数。

您的代码中存在错误

您的代码中有两个错误。

  1. Z 硬编码为格式模式字符串中的文字是错误的。 Z 是与 UTC 的偏移量(零),需要这样解析,否则您将在绝大多数 JVM 上得到错误的时间。
  2. SimpleDateFormat也只支持毫秒,精确到秒的小数点后三位。当分数全为零时,您不会注意到错误,但一旦有人在某处输入非零数字,您就会得到错误的结果。 SimpleDateFormat 无法正确处理 2、4 或 7 个小数位。

链接