【问题标题】:Converting string date time with +0000 To instant使用 +0000 将字符串日期时间转换为即时
【发布时间】:2021-11-30 09:54:57
【问题描述】:

如何将作为字符串 2018-08-10T18:25:00.000+0000 传递的日期时间转换为 Instant?我尝试了以下方法,但没有成功。

 public static Instant toInstant(final String timeStr) {
    if (StringUtils.isBlank(timeStr)) {
        throw new IllegalArgumentException("Invalid date time value passed [" + timeStr + "]");
    }

    try {
        return LocalDate.parse(timeStr).atStartOfDay().toInstant(ZoneOffset.UTC);
    } catch (Exception e) {
        try {
            return LocalDateTime.parse(timeStr).toInstant(ZoneOffset.UTC);
        } catch (Exception e1) {
            try {
                return ZonedDateTime.parse(timeStr).toInstant();
            } catch (Exception e2) {
                try {
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                    return LocalDateTime.parse(timeStr, formatter).toInstant(ZoneOffset.UTC);
                } catch (Exception e3) {
                    try {
                        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
                        return LocalDateTime.parse(timeStr, formatter).toInstant(ZoneOffset.UTC);
                    } catch (Exception e4) {
                        try {
                            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS");
                            return LocalDateTime.parse(timeStr, formatter).toInstant(ZoneOffset.UTC);
                        } catch (Exception e5) {
                        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
                            return LocalDateTime.parse(timeStr, formatter).toInstant(ZoneOffset.UTC);
                        } finally {
                            throw new IllegalArgumentException("Incorrect date time value passed [" + timeStr + "]");
                        }
                    }
                }
            }
        }
    }
}

【问题讨论】:

  • 简单的OffsetDateTime.parse(...).toInstant() 有什么问题?为什么要多次尝试?
  • "2018-08-10T18:25:00.000+0000" 不符合 ISO 标准,但 "2018-08-10T18:25:00.000+00:00" 符合标准。 (注意添加的冒号。)如果使用正确的格式,可以使用Instant instant = Instant.parse("2018-08-10T18:25:00.000+00:00");
  • @Seelenvirtuose Instant.parse 更短。
  • @k314159 该字符串确实符合 ISO 8601。有趣的是,单参数 OffsetDateTime.parse(CharSequence) 不接受它。参见例如Why can't OffsetDateTime parse '2016-08-24T18:38:05.507+0000' in Java 8

标签: java java-time timezone-offset datetimeformatter java.time.instant


【解决方案1】:

你的麻烦就在这里:

        } finally {
            throw new IllegalArgumentException("Incorrect date time value passed [" + timeStr + "]");
        }

您在这些行中解析成功(但可能给出不正确的结果):

            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
            return LocalDateTime.parse(timeStr, formatter).toInstant(ZoneOffset.UTC);

成功解析字符串后,在 finally 块中抛出异常。所以调用者没有收到结果,而是得到一个异常,并且必须认为解析或转换失败。

结果不正确?您对LocalDateTime 的解析会丢弃字符串+0000 中的UTC 偏移量。接下来您转换为Instant 假定为UTC,在这种情况下恰好与字符串一致。如果字符串中的偏移量不是+0000(例如+0100),您将得到不正确的Instant

其他答案显示了将字符串转换为Instant 的正确方法。

【讨论】:

    【解决方案2】:

    您的字符串2018-08-10T18:25:00.000+0000 的时区偏移量为+0000 小时,因此,您应该将其解析为OffsetDateTime,后者可以转换为Instant

    演示:

    import java.time.Instant;
    import java.time.OffsetDateTime;
    import java.time.format.DateTimeFormatter;
    import java.util.Locale;
    
    public class Main {
        public static void main(String args[]) {
            DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSZ", Locale.ENGLISH);
            OffsetDateTime odt = OffsetDateTime.parse("2018-08-10T18:25:00.000+0000", dtf);
            Instant instant = odt.toInstant();
            System.out.println(instant);
        }
    }
    

    输出:

    2018-08-10T18:25:00Z
    

    ONLINE DEMO

    上述解决方案中使用的DateTimeFormatter 仅适用于模式中指定的固定位数,例如在几分之一秒内只有 3 位数字。可以使用DateTimeFormatterBuilder 构建更好的DateTimeFormatter,如以下演示所示:

    import java.time.Instant;
    import java.time.OffsetDateTime;
    import java.time.format.DateTimeFormatter;
    import java.time.format.DateTimeFormatterBuilder;
    import java.util.Locale;
    
    public class Main {
        public static void main(String args[]) {
            DateTimeFormatter dtf = new DateTimeFormatterBuilder()
                                    .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
                                    .appendPattern("Z")
                                    .toFormatter(Locale.ENGLISH);
            OffsetDateTime odt = OffsetDateTime.parse("2018-08-10T18:25:00.000+0000", dtf);
            Instant instant = odt.toInstant();
            System.out.println(instant);
        }
    }
    

    输出:

    2018-08-10T18:25:00Z
    

    ONLINE DEMO

    通过 Trail: Date Time 了解有关 modern Date-Time API* 的更多信息。


    * 如果您正在为一个 Android 项目工作,并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaring。请注意,Android 8.0 Oreo 已经提供了support for java.time

    【讨论】:

      【解决方案3】:

      您可以将OffsetDateTimeDateTimeFormatter 一起使用。像这样的,

      public static Instant toInstant(final String timeStr) {
          DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
          OffsetDateTime dateTime = OffsetDateTime.parse(timeStr, formatter);
          return dateTime.toInstant();
      }
      

      【讨论】:

      • 这与 OP 已经在尝试的没有太大区别。
      猜你喜欢
      • 2015-09-17
      • 2022-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-31
      相关资源
      最近更新 更多