【问题标题】:Java 8 DateTime Format Date + OffsetJava 8 DateTime 格式日期 + 偏移量
【发布时间】:2017-09-29 11:24:31
【问题描述】:

我必须为 Web 服务构造一个 XMLGregorianCalendar,它需要一个格式为 yyyy-MM-dd+01:00 的日期,其中 + 之后的值来自时区偏移量。

到目前为止,我已经尝试过:

DateTimeFormatter formatterDateWithOffset = DateTimeFormatter.ofPattern("yyyy-MM-ddZZ");

XMLGregorianCalendar xcal = DatatypeFactory.newInstance()
    .newXMLGregorianCalendar(zonedDateTime.format(formatterDateWithOffset));

但这会导致IllegalArgumentExcpetion,因为格式化程序会生成2017-09-29+0200

是否可以为所需格式定义格式字符串?

【问题讨论】:

  • 你为什么使用 ZonedDateTime 而不是 LocalDateTime?
  • 你试过yyyy-MM-ddZZZZ吗? JavaDoc:“一个、两个或三个字母输出小时和分钟,不带冒号,如'+0130',...字母输出本地化偏移的完整形式”

标签: java date datetime formatting java-time


【解决方案1】:

如果您查看DateTimeFormatter 上的 JavaDoc,您会看到:

偏移 X 和 x: 这会根据模式字母的数量来格式化偏移。一个字母仅输出小时,例如“+01”,除非分钟不为零,在这种情况下也会输出分钟,例如“+0130”。两个字母输出小时和分钟,不带冒号,例如'+0130'。三个字母输出小时和分钟,带有冒号,例如'+01:30'。 ...当要输出的偏移量为零时,模式字母“X”(大写)将输出“Z”,而模式字母“x”(小写)将输出“+00”、“+0000”或'+00:00'。

因此DateTimeFormatter formatterDateWithOffset = DateTimeFormatter.ofPattern("yyyy-MM-ddxxx"); 应该可以工作。

在我的评论中,我建议使用 ZZZZ,因为 JavaDoc 也暗示了这一点,但它也会添加 GMT 部分(ZZZZZ 似乎工作,即使 JavaDoc 声明:“五个字母输出小时,分钟,可选秒,如果非零,冒号")。

【讨论】:

    【解决方案2】:

    您可以创建一个 XMLGregorianCalendar 实例,而不是解析,并将其传递给它的年、月等:

    XMLGregorianCalendar xcal = DatatypeFactory.newInstance().newXMLGregorianCalendar(year, month....)
    

    【讨论】:

      【解决方案3】:

      正如@Thomas's answer 所说,一种替代方法是使用xxx(或XXX),如explained in javadoc。它们之间的唯一区别是偏移量为零时:XXX 格式化为 Z,而 xxx 格式化为 +00:00

      Pattern  Count  Equivalent builder methods
      -------  -----  --------------------------
      XXX      3      appendOffset("+HH:MM","Z")
      xxx      3      appendOffset("+HH:MM","+00:00")
      

      无论如何,只需选择其中一个(我已经对两者进行了测试,使用 ZonedDateTimeZoneOffset.UTC 并且两者都有效):

      DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-ddXXX");
      String str = formatter.format(zonedDateTime);
      XMLGregorianCalendar xcal = DatatypeFactory.newInstance().newXMLGregorianCalendar(str);
      

      如果您有ZonedDateTime,将其转换为GregorianCalendar,然后将其传递给您的DatatypeFactory,会更容易:

      ZonedDateTime zonedDateTime = ZonedDateTime.now();
      GregorianCalendar cal = GregorianCalendar.from(zonedDateTime);
      XMLGregorianCalendar xcal = DatatypeFactory.newInstance().newXMLGregorianCalendar(cal);
      

      一个棘手的细节是,当使用上面的 String 模式(只有日期)时,结果会将时间字段(小时、分钟、秒和毫秒)设置为零,同时转换为 GregorianCalendar将使用ZonedDateTime中设置的时间。

      但您可以将时间设置为午夜,然后再将其转换为GregorianCalendar

      // convert to calendar (set the time to 00:00:00.000)
      GregorianCalendar cal = GregorianCalendar.from(zonedDateTime.with(LocalTime.MIDNIGHT));
      

      这样,结果将与使用String 相同。

      【讨论】:

        猜你喜欢
        • 2016-04-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-31
        • 2020-09-20
        • 2012-01-08
        • 1970-01-01
        相关资源
        最近更新 更多