【问题标题】:Unable to obtain ZonedDateTime from TemporalAccessor using DateTimeFormatter and ZonedDateTime in Java 8无法在 Java 8 中使用 DateTimeFormatter 和 ZonedDateTime 从 TemporalAccessor 获取 ZonedDateTime
【发布时间】:2014-06-29 01:51:51
【问题描述】:

我最近迁移到 Java 8,希望能更轻松地处理本地和分区时间。

但是,在我看来,在解析简单日期时,我遇到了一个简单的问题。

public static ZonedDateTime convertirAFecha(String fecha) throws Exception {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
            ConstantesFechas.FORMATO_DIA).withZone(
            obtenerZonaHorariaServidor());

    ZonedDateTime resultado = ZonedDateTime.parse(fecha, formatter);
    return resultado;
}

就我而言:

  • fecha 是 '15/06/2014'
  • ConstantesFechas.FORMATO_DIA 是 'dd/MM/yyyy'
  • obtenerZonaHorariaServidor 返回 ZoneId.systemDefault()

所以,这是一个简单的例子。但是,解析会抛出此异常:

java.time.format.DateTimeParseException: 文本 '15/06/2014' 不能 被解析:无法从 TemporalAccessor 获取 ZonedDateTime: {},ISO 解析为 java.time.format.Parsed 类型的 2014-06-15

有什么建议吗?我一直在尝试解析和使用 TemporalAccesor 的不同组合,但到目前为止没有任何运气。

【问题讨论】:

标签: java timezone java-8 datetime-format java-time


【解决方案1】:

这不起作用,因为您的输入(和您的格式化程序)没有时区信息。一种简单的方法是首先将您的日期解析为LocalDate(没有时间或时区信息),然后创建一个ZonedDateTime

public static ZonedDateTime convertirAFecha(String fecha) {
  DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
  LocalDate date = LocalDate.parse(fecha, formatter);

  ZonedDateTime resultado = date.atStartOfDay(ZoneId.systemDefault());
  return resultado;
}

【讨论】:

  • 是的,出现问题是因为格式化程序不提供时区。我编辑了您的答案以强调这一点。你是对的:-)。
  • 顺便说一句,除了使用 LocalDate 之外,另一个解决方案是使用 DateTimeFormatter.withZone(x) 为 Formatter 设置默认时区。然后你可以使用 ZonedDateTime,它总是有时区 x。
【解决方案2】:

这是一个错误,请参阅JDK-bug-log。根据该信息,Java 9 和 Java 8u20 的问题已解决。尝试下载最新的 Java 8 - 版本。 2014-05-12 今天:有一个early access release 8u20 可用。

更新:

我个人认为,由于您只有并期望“dd/MM/yyyy”作为模式,您应该使用LocalDate 作为@assylias 已经提出的主要类型。关于您的上下文,使用ZonedDateTime 几乎可以肯定是设计失败。你想对这种类型的对象做什么?我只能将专门的时区计算视为用例。而且您甚至不能将这些ZonedDateTime-objects 直接存储在数据库中,因此这种类型远没有许多人认为的有用。

与旧的GregorianCalendar-class(它是一种一体化类型)相比,我所描述的您的用例问题确实是Java-8 引入的一个新方面。用户必须开始考虑为他们的问题和用例选择合适的时间类型。

【讨论】:

  • 很好——尽管我相信操作仍然需要提供时间来将输入解析为 ZonedDateTime。
  • @assylias 是的,OP 应该至少在时间部分扩展模式或选择你的建议。这也可能取决于宽松的解析配置等。实际上我无法在我当前的位置使用 Java-8 测试这些细节。
  • 我将 ZonedDateTime 用于“dd/MM/yyyy”日期。这解决了我的问题since you only have and expect "dd/MM/yyyy" as pattern you should use LocalDate
  • @sleske 您说:“...OP 的代码不使用 withZone...” 但是 OP 提供的代码确实使用了withZone(…),见上文。所以提到的 JDK-bug 仍然与那些早期 JDK 版本中没有真正设置区域的问题相匹配。无论如何,其他大问题是:使用ZonedDateTime.parse(…) 而不是LocalDate.parse(…) 以及缺少时钟时间模式部分(如果坚持使用ZonedDateTime.parse(…))。
  • 哎呀,对不起,误读了这个问题……我的错。我删除了我的评论。
【解决方案3】:

简单来说就是行

ZonedDateTime.parse('2014-04-23', DateTimeFormatter.ISO_OFFSET_DATE_TIME)

抛出异常:

Text '2014-04-23' could not be parsed at index 10
java.time.format.DateTimeParseException: Text '2014-04-23' could not be parsed at index 10

这对我来说似乎是一个错误。

我使用了这个解决方法:

String dateAsStr = '2014-04-23';
if (dateAsStr.length() == 10) {
    dateAsStr += 'T00:00:00';
}
ZonedDateTime.parse(dateAsStr, DateTimeFormatter.ISO_OFFSET_DATE_TIME.withZone(ZoneId.systemDefault()));

【讨论】:

    【解决方案4】:

    如果来自 Google:

    而不是做:

    ZonedDateTime.from(new Date().toInstant());
    

    试试这个:

    ZonedDateTime.ofInstant(new Date(), ZoneId.of("UTC")); 
    

    【讨论】:

      【解决方案5】:

      只是一个示例转换,我相信有些人会得到下面的异常

      (java.time.DateTimeException: Unable to obtain LocalDateTime from TemporalAccessor: 2014-10-24T18:22:09.800Z of type java.time.Instant)
      

      如果他们尝试

      LocalDateTime localDateTime = LocalDateTime.from(new Date().toInstant());
      

      要解决问题,请传入Zone -

      LocalDateTime localDateTime = LocalDateTime.from(new Date()
              .toInstant().atZone(ZoneId.of("UTC")));
      

      【讨论】:

        猜你喜欢
        • 2019-04-16
        • 2016-06-26
        • 1970-01-01
        • 2019-08-19
        • 1970-01-01
        • 1970-01-01
        • 2016-05-02
        • 1970-01-01
        • 2020-05-19
        相关资源
        最近更新 更多