为什么这不长时间

时间:2018-04-11 13:22:37

标签: java casting

我今天遇到了来自此类代码的奇怪的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?

1 个答案:

答案 0 :(得分:3)

所有人都说过,但我认为它应该得到答案。将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日期和时间API java.time。与过时的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开始)。幸运的是,现代的库类可以完全避免繁殖。并发出任何溢出信号。

链接