Java中为何表达式未自动转为long类型,导致日期计算错误?
解析Java日期计算中的整数溢出问题
这真是个开发者常踩的整数溢出坑!我来帮你把这个问题拆解清楚:
问题重现
你写出的这段代码:
new Date(System.currentTimeMillis() - 1000 * 60 * 60 * 24 * 31)
原本想生成当前时间31天前的日期,结果却得到了16天后的未来时间,核心原因就是int类型的整数溢出,而且和Java的表达式运算规则直接相关。
为什么会溢出?
我们先算一下这段乘法的预期值:1000 * 60 * 60 * 24 * 31 = 2,678,400,000,但Java里int类型的最大值是2^31-1 = 2,147,483,647,显然这个结果已经超出了int的范围,会触发溢出回绕——溢出后的数值会变成负数(具体是-1,616,567,296)。
这里的关键误区是:你以为System.currentTimeMillis()是long类型,整个表达式会自动转为long计算,但Java的类型提升规则是先计算子表达式,再进行整体的类型转换。乘法部分1000 * 60 * 60 * 24 * 31的所有操作数都是int,所以会先按int类型计算,溢出得到负数后,才会被提升为long类型和System.currentTimeMillis()做减法。
相当于用当前时间减去一个负数,也就是加上这个负数的绝对值,结果自然就变成了未来的日期。
解决方法
把乘法表达式中的第一个操作数改为long类型即可,比如1000L:
new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 31)
因为1000L是long类型,后续每一步乘法都会把其他int操作数自动提升为long类型,整个乘法结果就是正确的2,678,400,000L,再用当前时间减去这个值,就能得到31天前的正确日期。
内容的提问来源于stack exchange,提问作者Pavel Niedoba




