【问题标题】:Convert String without ZonedId to OffsetDateTime将没有 ZonedId 的字符串转换为 OffsetDateTime
【发布时间】:2018-05-18 14:38:44
【问题描述】:

我想将字符串转换为 OffsetDateTime 数据类型。该字符串具有以下形状:

  2017-11-27T19:06:03

我尝试了两种方法:

方法 1

    public static OffsetDateTime convertString(String timestamp) {
        java.time.format.DateTimeFormatter formatter = new java.time.format.DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .append(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE)
            .appendLiteral('T')
            .appendValue(HOUR_OF_DAY, 2)
            .appendLiteral(':')
            .appendValue(MINUTE_OF_HOUR, 2)
            .optionalStart()
            .appendLiteral(':')
            .appendValue(SECOND_OF_MINUTE, 2)
            .toFormatter();


        return OffsetDateTime.parse(timestamp, formatter);
    }

方法2:

    public static OffsetDateTime convertString(String timestamp) {
        java.time.format.DateTimeFormatter parser = java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
        java.time.LocalDateTime dt = java.time.LocalDateTime.parse(timestamp, parser);
        ZonedDateTime zdt = ZonedDateTime.of(dt, java.time.ZoneId.of("UTC"));
        return OffsetDateTime.from(zdt);
    }

第一种方法不起作用,因为它抱怨以下内容:

java.time.format.DateTimeParseException:无法解析文本“2017-11-27T19:02:42”:无法从 TemporalAccessor:{} 获取 OffsetDateTime,ISO 解析为 2017-11-27T19:02:42 java.time.format.Parsed 类型的

据我了解,这是因为字符串没有 ZoneId。如何在格式化程序上覆盖 ZoneId 以便忽略它?

第二种方法来自 from this question 并且有效,但它需要 2 次额外的转换,我想避免这些额外的转换。

我们将不胜感激。

【问题讨论】:

  • 您的预期结果是什么?由于字符串中没有时区或偏移量,因此您需要确定要使用的偏移量。

标签: java datetime timezone-offset zoneddatetime


【解决方案1】:

要从没有偏移量或时区的字符串中获取OffsetDateTime,您需要确定偏移量或获取偏移量的方法。最明显的方法是,如果您知道要在哪个时区解释日期时间。例如:

    OffsetDateTime dateTime = LocalDateTime.parse(timestamp)
            .atZone(ZoneId.of("Asia/Chongqing"))
            .toOffsetDateTime();
    System.out.println(dateTime);

使用问题中的字符串输出:

2017-11-27T19:06:03+08:00

不要害怕从LocalDateTimeZonedDateTime 再到OffsetDateTime 的两次转换。使用java.time,它们不仅易于操作,而且易于阅读。

如果您知道偏移量,只需使用它,那么您只需要一次转换(我在示例中使用了一个无意义的偏移量,因此您必须自己选择):

    OffsetDateTime dateTime = LocalDateTime.parse(timestamp)
            .atOffset(ZoneOffset.ofTotalSeconds(-36953));
    System.out.println(dateTime);

输出:

2017-11-27T19:06:03-10:15:53

您可以指定所需的偏移量,例如 ZoneOffset.of("+08:00")ZoneOffset.ofHours(8)

但是回答你的问题(现在是时候了)。

如何在格式化程序上覆盖 ZoneId 以便忽略它?

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
            .parseDefaulting(ChronoField.OFFSET_SECONDS, -36953)
            .toFormatter();
    OffsetDateTime dateTime = OffsetDateTime.parse(timestamp, formatter);
    System.out.println(dateTime);

输出与前一个相同(同样,您需要选择一个适合您的情况的偏移量)。

【讨论】:

    【解决方案2】:

    最后,我通过以下代码解决了这个问题:

        public static OffsetDateTime convertString(String timestamp) {
            java.time.format.DateTimeFormatter formatter = new java.time.format.DateTimeFormatterBuilder()
                .parseCaseInsensitive()
                .append(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE)
                .appendLiteral('T')
                .appendValue(HOUR_OF_DAY, 2)
                .appendLiteral(':')
                .appendValue(MINUTE_OF_HOUR, 2)
                .optionalStart()
                .appendLiteral(':')
                .appendValue(SECOND_OF_MINUTE, 2)
                .toFormatter();
    
        return LocalDateTime.parse(timestamp, formatter)
                .atOffset(java.time.ZoneOffset.UTC);
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-02
      • 1970-01-01
      • 1970-01-01
      • 2015-01-06
      • 2020-03-04
      • 2015-05-03
      • 2019-09-24
      • 2019-12-18
      相关资源
      最近更新 更多