【问题标题】:Why is this not casting to long为什么这不是很长
【发布时间】:2018-04-12 04:04:47
【问题描述】:

我今天遇到了来自此类代码的奇怪的 java 转换问题

new Date(System.currentTimeMillis() - 1000 * 60 * 60 * 24 * 31)

这应该在现在 31 天之前给出日期,但在 16 天之后返回日期。这显然是因为 1000 * 60 * 60 * 24 * 31 被评估为整数并溢出。

new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 31) 按预期工作

我认为 java 应该将整个表达式转换为 Long 因为第一个操作数是 Long System.currentTimeMillis() 但由于某种我不明白的原因在这里没有发生。硬编码常量是否有一些例外是 int ?

【问题讨论】:

  • 为什么不直接使用Java提供的LocalDateTime呢?这样就可以了:LocalDateTime.now().minusDays(31);
  • 哦,还要回答您的问题:您所有的数字都是整数,* 运算符优先于 - 运算符,因此只有在溢出已经发生之后才会进行转换。
  • 1000 * 60 * 60 * 24 * 31 是一个整数。然后你从一个 long 中减去它并得到另一个 long。但是 int 在减法之前就已经溢出了。
  • 现在我明白了,小学数学,就像System.currentTimeMillis() - (1000 * 60 * 60 * 24 * 31) for java
  • 这意味着使首字母缩写词发音:-) 实际上,它的意思是“订单”;即权力,根源等

标签: java casting


【解决方案1】:

都说了,但我认为它应该得到一个答案。将ZonedDateTime 类与ZoneId 一起使用。

    ZonedDateTime aMonthAgo = ZonedDateTime.now(ZoneId.of("Indian/Comoro")).minusMonths(1);

刚刚在我的电脑上输出(4月11日):

2018-03-11T19:57:47.517032+03:00[印度/科摩罗]

我减去一个月,这意味着 28、29、30 或 31 天,具体取决于我所在的月份和上个月的天数。如果您无条件想要 31 天,当然可以:

    ZonedDateTime thirtyoneDaysAgo 
            = ZonedDateTime.now(ZoneId.of("Indian/Comoro")).minusDays(31);

由于 3 月有 31 天,所以在这种情况下结果是相同的。不会总是这样。

我正在使用并推荐 java.time,这是现代 Java 日期和时间 API。与过时的 Date 类相比,它使用起来更好,更不容易出错。

你的代码出了什么问题?

关于operator precedence1000 * 60 * 60 * 24 * 31int 值组成。是的,整型文字的类型为 int,除非它们具有 L 后缀。因为乘法是在减法之前执行的(正如您已经预料到的那样),所以结果也是 int,但它会溢出,因为结果将大于 int 可以容纳的最大数字。不幸的是,Java 没有通知你溢出,它只是给你一个错误的结果,这里是-1616567296,大约 -19 天。减去这些后,您会得到大约 19 天后的日期和时间。

作为一种习惯,使用括号、L 后缀和underscore-grouping 以提高可读性。

( System.currentTimeMillis() - ( 1_000L * 60L * 60L * 24L * 31L ) )

如果您想知道溢出,您可以使用Math.multiplyExact​() 进行乘法运算(从 Java 8 开始)。幸运的是,现代库类完全避免了乘法。并发出任何溢出信号。

链接

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-02
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    相关资源
    最近更新 更多