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

背景

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

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);
  }
}

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

(0)

相关推荐

  • java时间戳与日期相互转换工具详解

    本文为大家分享了java日期与时间戳相互转换大全,供大家参考,具体内容如下 package com.crm.util; import java.math.BigDecimal; import java.text.DecimalFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; /** * @auth

  • 深入理解java long 存储时间戳

    存储时间打算用时间戳来存储,打算用long类型来代表时间戳,但是在用long类型存储时间戳的时候出了点问提. 在写单元测试的时候,用一个long类型来存储时间戳,发现编译器报错了 刚开始猜想可能是因为long不够大,存储不了.然后用double类型来存: 发现还是报错了,仔细想想不对,double存储的数量应该时很大的,不会连时间戳都存储不了. 在后面加上小数点之后,居然可以存了: 加了小数点之后就能存了,仔细一想,之前没加小数点的时候他是整数,加了小数点之后变成了浮点数,猜测之前没加上小数点的

  • Java获取凌晨时间戳的方法分析

    本文实例讲述了Java获取凌晨时间戳的方法.分享给大家供大家参考,具体如下: 这两天有一个需求是查询用户匹配的推荐信息,包含一个有效时间段,以天为单位,0时0分0秒这种. 通常java中有两种方案: 第一种:使用Calendar.这种比较简单,也最常见.代码如下: package dateTimeDemo; import java.util.Calendar; public class timeDemo { public static void main(String[] args) { //

  • Java获取精确到秒的时间戳方法

    本文实例为大家分享了Android九宫格图片展示的具体代码,供大家参考,具体内容如下 1.时间戳简介: 时间戳的定义:通常是一个字符序列,唯一地标识某一刻的时间.数字时间戳技术是数字签名技术一种变种的应用.是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数(引用自百度百科) 2.Java中的时间戳: 在不同的开发语言中,获取到的时间戳的长度是不同的,例如C++中的时间戳是精确到秒的,但是Java中的时间戳是精确到毫秒的,这

  • java中如何获取时间戳的方法实例

    前言 数字时间戳技术是数字签名技术一种变种的应用.是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数(引用自百度百科) 在java开发过程中经常会遇到统计某一天或是某一个月的数据,因此常常需要获取截取数据的两个时间戳(比如统计今天的数据,则需要获取一个开始时间为今天零点以及一个结束时间为明天零点),然后根据数据相关的时间是否在该时间区间内来判断是否将其计入统计数据中. 一.java获取时间戳 话不多说,首先我们先拿上面的例

  • java时间戳转日期格式的实现代码

    如下所示: 复制代码 代码如下: String beginDate="1328007600000"; SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd"); String sd = sdf.format(new Date(Long.parseLong(beginDate))); System.out.println(sd);

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

    背景 今天在跑定时任务的过程中,发现有一个任务在设置数据的查询时间范围异常,出现了开始时间戳比结束时间戳大的奇怪现象,计算时间戳的代码大致如下. package com.lingyejun.authenticator; public class IntegerTest { public static void main(String[] args) { long endTime = System.currentTimeMillis(); long startTime = endTime - 30

  • vue3中cookie的详细使用过程

    目录 前言 1.vue中cookie的安装 2.登录过程中cookies的设置 3.在需要的地方拿到之前存入的cookies 总结 前言 cookie使用最多的地方想必是保存用户的账号与密码,可以避免用户每次登录时都要重新输入 1.vue中cookie的安装 在终端中输入命令npm install vue-cookies --save,即可安装cookies,安装之后在main.js文件中写下以下代码 import { createApp } from 'vue' import VueCooki

  • java中的数学计算函数的总结

    java中的数学计算函数 Math类: java.lang.Math类中包含基本的数字操作,如指数.对数.平方根和三角函数. java.math是一个包,提供用于执行任意精度整数(BigInteger)算法和任意精度小数(BigDecimal)算法的类. java.lang.Math类中包含E和PI两个静态常量,以及进行科学计算的类(static)方法,可以直接通过类名调用. public static final Double E = 2.7182818284590452354 public

  • PHP中UNIX时间戳和日期间的转换与计算实例

    UNIX时间戳是保存日期和时间的一种紧凑简洁的方法,是大多数UNIX系统中保存当前日期和时间的一种方法,也是在大多数计算机语言中表示日期和时间的一种标准格式.以32位整数表示格林威治标准时间,例如,使用证书11230499325表示当前时间的时间戳.UNIX时间戳是从1970年1月1日零点(UTC/GMT的午夜)开始起到当前时间所经过的秒数.1970年1月1日零点作为所有日期计算的基础,这个日期通常成为UNIX纪元. 因为UNIX时间戳是一个32位的数字格式,所以特别适用于计算机处理,例如计算两

  • Java实现多线程断点下载实例代码(下载过程中可以暂停)

    线程可以理解为下载的通道,一个线程就是一个文件的下载通道,多线程也就是同时开启好几个下载通道.当服务器提供下载服务时,使用下载者是共享带宽的,在优先级相同的情况下,总服务器会对总下载线程进行平均分配.不难理解,如果你线程多的话,那下载的越快. 现流行的下载软件都支持多线程,且支持中途暂停下载,再次开始时不会从头开始下载. 两种功能的实现步骤如下: (1)连接到下载资源文件时,首先判断资源文件大小,同步的在本地创建一个大小相同的临时文件用于存储下载数据. (2)根据线程数量确定每个线程所需下载的文

  • java中处理socket通信过程中粘包的情况

    这两天学习了java中处理socket通信过程中粘包的情况,而且很重要,所以,今天添加一点小笔记. 处理粘包程序是客户端的接受消息线程: 客户端: import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.Reader; import java.net.Socket; impo

  • java计算给定字符串中出现次数最多的字母和该字母出现次数的方法

    本文实例讲述了java计算给定字符串中出现次数最多的字母和该字母出现次数的方法.分享给大家供大家参考,具体如下: import Java.util.Collections; import java.util.Map; import java.util.TreeMap; public class TestStringSplict { public static void main(String[] args){ String str = "aaaaaaacccccccccccccccccccccc

  • 简单探索 Java 中的惰性计算

    前言 惰性计算(尽可能延迟表达式求值)是许多函数式编程语言的特性.惰性集合在需要时提供其元素,无需预先计算它们,这带来了一些好处. 首先,您可以将耗时的计算推迟到绝对需要的时候.其次,您可以创造无限个集合,只要它们继续收到请求,就会继续提供元素.第三,map 和 filter 等函数的惰性使用让您能够得到更高效的代码(请参阅 参考资料 中的链接,加入由 Brian Goetz 组织的相关讨论).Java 并没有为惰性提供原生支持,但一些框架和后继语言支持这种惰性. 假定使用此伪代码片段来打印列表

  • 解决pytorch GPU 计算过程中出现内存耗尽的问题

    Pytorch GPU运算过程中会出现:"cuda runtime error(2): out of memory"这样的错误.通常,这种错误是由于在循环中使用全局变量当做累加器,且累加梯度信息的缘故,用官方的说法就是:"accumulate history across your training loop".在默认情况下,开启梯度计算的Tensor变量是会在GPU保持他的历史数据的,所以在编程或者调试过程中应该尽力避免在循环中累加梯度信息. 下面举个栗子: 上代

  • Java中获取时间戳的三种方式对比实现

    Java中获取时间戳 三种方式对比 最近项目开发过程中发现了项目中获取时间戳的业务.而获取时间戳有以下三种方式,首先先声明推荐使用System类来获取时间戳,下面一起看一看三种方式. 1.System.currentTimeMillis() System类中的currentTimeMillis()方法是三种方式中效率最好的,运行时间最短.开发中如果设计到效率问题,推荐使用此种方式获取. System.currentTimeMillis() 2.new Date().getTime() 除了Sys

随机推荐