【问题标题】:Why is Instant.now() sometimes formatted differently?为什么 Instant.now() 有时格式不同?
【发布时间】:2018-11-05 06:06:48
【问题描述】:

我的代码如下所示:

String PROPER_DATE_FORMAT = "yyyy-MM-dd";
String format = "yyyy-MM-dd'T'HH:mm:ss.SSSX";

SimpleDateFormat sdf = new SimpleDateFormat(format);
Date d = sdf.parse(Instant.now().toString());
SimpleDateFormat properFormat = new SimpleDateFormat(PROPER_DATE_FORMAT);
String formatterDate = properFormat.format(d);

现在,大多数情况下,这段代码都能正常工作,但我会时不时地使用 Instant.now() 返回 2018-05-25T18:56:09Z,然后它会在格式不匹配的情况下抛出异常。

为什么有时会不一致?

例外是java.lang.RuntimeException: java.text.ParseException: Unparseable date: "2018-05-25T18:56:09Z"

通常,当Instant.now().toString() 确实返回具有上述格式的字符串时。同样,这段代码大部分时间都有效,但也有几次无效,我不知道为什么。

我想是否是因为最后有一个零但没有显示但我不相信因为我能够得到一个值 2018-05-25T20:06:58.900Z 结果Instant.now().toString()

【问题讨论】:

  • 谢谢,我已经包含了异常情况
  • 为什么要将瞬间转换为字符串只是为了将其解析为日期?为什么不写Date d = new Date(Instant.now().toEpochMilli());
  • Instant.toString() 仅在必要时输出millis 的数字(如果它们不是000)。因此,您有千分之一的机会准确地击中您的代码将失败的秒(所有毫秒数字为零)
  • 既然你可以使用java.time,现代Java 日期和时间API,也不要使用Date,它已经过时并且设计很差。仅当您需要 Date 用于无法更改的旧版 API 时。仅在这种情况下,使用Date.from(Instant) 进行转换。并且在任何情况下完全使用臭名昭著的麻烦SimpleDateFormat
  • 顺便说一句,在我计算机上的 Java 9 上,Instant.now().toString() 产生类似 2018-05-26T05:56:50.294304Z 的东西,您的代码会将其转换为 2018 年 5 月 26 日星期六 08:01:44 CEST 的 Date . CEST 位于偏移 +02:00,因此您注意到时间不正确。

标签: java java-8 java-time date


【解决方案1】:

当纳秒为零时,它不包含在格式化字符串中。所以输出将被格式化为“yyyy-MM-dd'T'HH:mm:ssX”

您可以通过以下方式看到差异:

public static void main(String[] args) throws ParseException {
        final Instant now = Instant.now();
        System.out.println("Now:\t" +  now);

        final Instant zeroedNow = now.with(ChronoField.NANO_OF_SECOND, 0);
        System.out.println("Zeroed:\t" + zeroedNow);
} 

输出看起来像

Now:    2018-05-25T20:23:54.208Z
Zeroed: 2018-05-25T20:23:54Z

【讨论】:

    【解决方案2】:

    您的代码失败,因为 Instant.toString() 记录为

    使用的格式与 DateTimeFormatter.ISO_INSTANT 相同。

    根据DateTimeFormatter.html#ISO_INSTANT

    纳秒根据需要输出零、三、六或九位数字

    因此,您有千分之一的机会获得毫秒为 000 并且您的代码失败的 Instant。


    无论如何,您的代码过于复杂,可以替换为

    String formattedDate = DateTimeFormatter.ofPattern("yyyy-MM-dd")
        .withZone(ZoneId.systemDefault())
        .format(Instant.now());
    

    无需将Instant转换为String,只需将其解析为Date,然后再次转换为String。

    【讨论】:

    • 问的不是这个。
    • 我同意@bruno 的观点——虽然你的(可能)是进行这种转换的更好方法,但它不能回答 “为什么有时 Instant.now()格式不同?”
    • @OleV.V.感谢您的评论 - 我已经检查并更新了我的替换代码。
    【解决方案3】:

    回答您的问题:“Instant.now() 有时格式不同?”。让我们看看Instance.now().toString()是如何实现的:

    Instant.now().toString() 来源

    public String toString() {
        return DateTimeFormatter.ISO_INSTANT.format(this);
    }
    

    Javadoc

    DateTimeFormatter.ISO_INSTANT

    https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_INSTANT

     When formatting, the second-of-minute is always output.
     The nano-of-second outputs zero, three, six or nine digits digits as necessary.
    

    从这个 javadoc 中,我们了解到 Instance.now.toString() 并不总是 24 长度

    如果毫秒为 000 -> 它将产生你得到的格式:

    2018-05-25T18:56:09Z - 20 长度

    不是

    2018-05-25T18:56:09.000Z - 24 长度

    一切都清楚了吗?

    【讨论】:

      猜你喜欢
      • 2019-02-12
      • 2016-05-13
      • 1970-01-01
      • 1970-01-01
      • 2022-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多