【问题标题】:Java String date to XMLGregorianCalendar whit format 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'
【发布时间】:2020-03-27 14:06:14
【问题描述】:

我有一个带有以下格式的日期标签的肥皂网络服务

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 在格式中保留七个零?

【问题讨论】:

  • 我建议你不要使用SimpleDateFormatDate。这些类设计不良且过时,尤其是前者,尤其是出了名的麻烦。 XMLGregorianCalendar 也很旧,SimpleDateFormat 只处理毫秒,正好是三位小数。而是使用来自java.time, the modern Java date and time APIOffsetDateTimeDateTimeFormatter
  • 您是从生产代码中的"2019-12-01T04:00:00.0000000Z" 之类的字符串开始的,还是只是为了在问题中获取示例值?
  • 我没有做网络服务,我只需要做使用它的客户端并且日期以这种格式出现

标签: java date datetime soap xmlgregoriancalendar


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    你可能不需要 7 位小数

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

    日期时间按以下格式指定“YYYY-MM-DDThh:mm:ss”……

    不过,引用 W3C 的 XML Schema Part 2: Datatypes Second Edition,允许“精确到任意精度级别”的小数部分。因此,如果您的 Web 服务坚持精确到小数点后 7 位,这是一个特殊且不寻常的限制。你可能想挑战它。

    XMLGregorianCalendar 的替代品

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

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

    这个 sn-p 输出:

    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

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

    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。这些类设计不佳且早已过时,尤其是前者,尤其是出了名的麻烦。 GregorianCalendar 也是如此。我们有时可能会将它与XMLGregorianCalendar 一起使用,因为两者之间存在转换(如您的问题中所使用的那样)。 GregorianCalendar只有毫秒精度,所以你永远不会通过这样的转换得到7位小数。

    代码中的错误

    您的代码中有两个错误。

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

    链接

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-07-05
      • 1970-01-01
      • 2017-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多