【问题标题】:How do I get an Instant object with the timestamp 48962-08-06T23:16:59.000Z in Java如何在 Java 中获取时间戳为 48962-08-06T23:16:59.000Z 的 Instant 对象
【发布时间】:2020-12-29 18:53:32
【问题描述】:

我有一个日期字符串,我想将其解析为 Instant 48962-08-06T23:16:59.000Z 但无法做到,因为大多数标准 DateTimeFormatter 规则都不支持它。

参考:https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html

这是我尝试做的,使用我的自定义格式化程序

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .appendValue(YEAR, 5, 10, SignStyle.EXCEEDS_PAD)
            .appendLiteral('-')
            .appendValue(MONTH_OF_YEAR, 2)
            .appendLiteral('-')
            .appendValue(DAY_OF_MONTH, 2)
            .appendLiteral('T')
            .appendValue(HOUR_OF_DAY, 2).appendLiteral(':')
            .appendValue(MINUTE_OF_HOUR, 2).appendLiteral(':')
            .appendValue(SECOND_OF_MINUTE, 2)
            .appendFraction(NANO_OF_SECOND, 0, 9, true)
            .appendLiteral('Z')
            .toFormatter();
    
    Instant value = Instant.from(formatter.parse("48962-08-06T23:16:59.000Z"));

但它失败了Unable to obtain Instant from TemporalAccessor: {},ISO resolved to +48962-08-06T23:16:59 of type java.time.format.Parsed

【问题讨论】:

  • 这5位数字代表什么年份?是来自某个特定文化的日历,还是您真的想解析那么远的未来一年?
  • @Fildor Instant 支持 max to +1000000000-12-31T23:59:59.999999999Z 那么我们如何解析呢?
  • @Fildor 对我来说这个问题似乎很明显,尽管他可能应该提到它。那就是“如何获得时间戳为 48962-08-06T23:16:59.000Z 的 Instant 对象?”
  • @deHaar 只是我们需要解析的某个未来日期
  • 查看我对 deHaars 答案的评论:高年份数字是一个红鲱鱼,问题与时区有关(或在这种情况下缺少时区)。

标签: java datetime java-8


【解决方案1】:

我同意您的观点,即使用构建器是一个不错的解决方案。以下是用 4 位和 5 位数字解析年份:

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .appendValue(ChronoField.YEAR, 4, 5, SignStyle.NOT_NEGATIVE)
            .appendPattern("-MM-dd'T'")
            .append(DateTimeFormatter.ISO_LOCAL_TIME)
            .appendOffsetId()
            .toFormatter();
    
    String dateTime = "48962-08-06T23:16:59.000Z";
    
    Instant i = formatter.parse(dateTime, Instant::from);
    
    System.out.println(i);

sn-p 的输出是:

+48962-08-06T23:16:59Z

您的基本问题是您的字符串不符合 ISO 8601,java.time 的类将其解析为默认标准,即没有任何显式格式化程序。在 ISO 8601 中可以允许超过 4 位的年份,但是需要一个符号(您也可以在上面的输出中看到)。

您的代码出了什么问题? Joachim Sauer 在评论中是正确的:硬编码 Z 作为文字是错误的。它与 UTC 的偏移量为 0,需要将其解析为偏移量。由于您的格式化程序没有解析任何偏移量,它无法从解析的信息中确定一个点 int 时间,一个瞬间。这就是您的错误消息的意思:

Unable to obtain Instant from TemporalAccessor: {},ISO resolved to +48962-08-06T23:16:59 of type java.time.format.Parsed

【讨论】:

    【解决方案2】:

    在我的机器上,下面的代码解析你未来的一年:

    public static void main(String[] args) {
        String dateTime = "48962-08-06T23:16:59.000Z";
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuuu-MM-dd'T'HH:mm:ss.SSSz");
        Instant instant = Instant.from(dtf.parse(dateTime));
        System.out.println(instant);
    }
    

    和输出

    +48962-08-06T23:16:59Z
    

    我认为您的代码的问题是其中一行(或两行)

                .appendFraction(NANO_OF_SECOND, 0, 9, true)
                .appendLiteral('Z')
    

    因为String 中的点之后和Z 之前的三位数字可能不是秒的纳秒,而是秒的分数。
    另一条线也可能有问题,但我真的不能告诉你为什么。我只知道当模式中的z(小写)更改为Z(大写)时,我的回答会抛出异常。

    您可以在 DateTimeFormatter 中调整它,然后重试,可能会奏效。

    【讨论】:

    • 肯定是Z,这就是问题所在。 OP 解析基本上是LocalDateTime:即没有时区信息的日期和时间。在不知道要应用哪个时区的情况下,无法将其转换为Instant。所以他们需要要么在外部提供时区(通过转换为LocalDateTime,然后使用toInstant(),提供时区)或更改解析规则以将Z解释为UTC通过将.appendLiteral('Z') 替换为.appendZoneId() 来指示。
    猜你喜欢
    • 2021-04-21
    • 1970-01-01
    • 2021-10-21
    • 1970-01-01
    • 1970-01-01
    • 2016-11-26
    • 2020-10-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多