Java中在时间戳计算的过程中遇到的数据溢出问题

栏目: Java · 发布时间: 6年前

内容简介:今天在跑定时任务的过程中,发现有一个任务在设置数据的查询时间范围异常,出现了开始时间戳比结束时间戳大的奇怪现象,计算时间戳的代码大致如下。先放出结论:因为java中整数默认是int类型,在计算的过程中我们将上面的代码稍稍改造一下,方便我们确认定位问题,调整后的代码如下:

背景

今天在跑定时任务的过程中,发现有一个任务在设置数据的查询时间范围异常,出现了开始时间戳比结束时间戳大的奇怪现象,计算时间戳的代码大致如下。

package com.lingyejun.authenticator;
 
public class IntegerTest {
 
    public static void main(String[] args) {
        long endTime = System.currentTimeMillis();
        long startTime = endTime - 30 * 24 * 60 * 60 * 1000;
 
        System.out.println("end   : " + endTime);
        System.out.println("start : " + startTime);
    }
}

先放出结论:因为 java 中整数默认是int类型,在计算的过程中 30 * 24 * 60 * 60 * 1000 计算结果大于 Integer.MAX_VALUE ,所以出现了 数据溢出 ,从而导致了计算结果不准确的问题。

验证

我们将上面的代码稍稍改造一下,方便我们确认定位问题,调整后的代码如下:

package com.lingyejun.authenticator;
 
public class IntegerTest {
 
    public static long calcStartTime(long endTime, long minusMills) {
        System.out.println("end  : " + endTime + " minus mills : " + minusMills);
        long startTime = endTime - minusMills;
        System.out.println("start: " + startTime);
        return startTime;
    }
 
    public static void main(String[] args) {
        long nowTime = System.currentTimeMillis();
        long a = 30 * 24 * 60 * 60 * 1000;
        calcStartTime(nowTime, a);
    }
} 

结果如下:

end  : 1560869539864 minus mills : -1702967296
start: 1562572507160

这和我们的预期不一样,因为30 * 86400000 = 2592000000,但是计算出来却是:-1702967296。

到这里想必大家都知道原因了,这是因为java中整数的默认类型是整型int,而int的最大值是2147483647,

在代码中java是先计算右值,再赋值给long变量的。在计算右值的过程中(int型相乘)发生溢出,然后将溢出后截断的值赋给变量,导致了结果不准确。

将代码做一下小小的改动,再看一下。

package com.lingyejun.authenticator;
 
public class IntegerTest {
 
    public static long calcStartTime(long endTime, long minusMills) {
        System.out.println("end  : " + endTime + " minus mills : " + minusMills);
        long startTime = endTime - minusMills;
        System.out.println("start: " + startTime);
        return startTime;
    }
 
    public static void main(String[] args) {
        long nowTime = System.currentTimeMillis();
        long a = 30 * 24 * 60 * 60 * 1000L;
        calcStartTime(nowTime, a);
    }
}

结果为

end  : 1560869539864 minus mills : 2592000000
start: 1558277539864

似乎这样应该就没有什么问题了,但是这样就真的保险了吗,如果我要把30调整为24856 (Integer.MAX_VALUE / 86400 = 24855) ,即改为: long a = 24856 * 24 * 60 * 60 * 1000L 那么同样会出现溢出。

因为java的运算规则从左到右,再与最后一个long型的1000相乘之前就已经溢出,所以结果也不对,正确的方式应该如下: long a = 24856L * 24 * 60 * 60 * 1000

package com.lingyejun.authenticator;
 
public class IntegerTest {
 
    public static long calcStartTime(long endTime, long minusMills) {
        System.out.println("end  : " + endTime + " minus mills : " + minusMills);
        long startTime = endTime - minusMills;
        System.out.println("start: " + startTime);
        return startTime;
    }
 
    public static void main(String[] args) {
        long a = 30L * 24 * 60 * 60 * 1000;
        calcStartTime(nowTime, a);
    }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Data Structures and Algorithms

Data Structures and Algorithms

Alfred V. Aho、Jeffrey D. Ullman、John E. Hopcroft / Addison Wesley / 1983-1-11 / USD 74.20

The authors' treatment of data structures in Data Structures and Algorithms is unified by an informal notion of "abstract data types," allowing readers to compare different implementations of the same......一起来看看 《Data Structures and Algorithms》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码