为什么这不长时间
今天我从这样的代码中得到了奇怪的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?
这一切都说了,但我认为它应该得到答案。 将ZonedDateTime
类与ZoneId
一起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
类相比,使用它更好,并且更不容易出错。
您的代码出了什么问题?
这是关于运营商优先权的 。 1000 * 60 * 60 * 24 * 31
由int
值组成。 是的,整数文字的类型为int
除非它们具有L
后缀。 因为乘法是在减法之前执行的(正如您所预期的那样),结果也是一个int
,但它会溢出,因为结果将大于int
可以容纳的最大数。 不幸的是,Java没有通知你溢出,它只是给你一个错误的结果,这里-1616567296
,大约-19天。 减去这些时间后,您将获得约19天的日期和时间。
作为一种习惯,使用括号, L
后缀和下划线分组以提高可读性。
( System.currentTimeMillis() - ( 1_000L * 60L * 60L * 24L * 31L ) )
如果您想了解溢出,可以使用Math.multiplyExact()
进行乘法(从Java 8开始)。 幸运的是,现代的库类可以完全避免繁殖。 并发出任何溢出信号。
链接
- Oracle教程:Date Time解释了如何使用
java.time
。 -
Math.multiplyExact() documentation