今天在做一个需求,要求客户只能在到期提前30天续费,于是写了这个判断:
if (addedProduct.getExpTime().getTime() > System.currentTimeMillis() + 30 * 24 * 3600 * 1000) {
// 只能提前30天续费
throw new CodeTipException(CodeTip.TIP_APPLY_PARAM_ERROR);
}
但是逻辑一直都到不了这里,为什么呢?
于是debug把打印出来
我就觉得奇怪了?为啥加上30天的时间戳之后,反而变小了呢?
看到这里,我就想,是不是编译器出错了呢,我明明是要加法哦,怎么变成减法了呢?
于是我把30 * 24 * 3600 * 1000打印出来,问题找到了
为何这个是负数呢?一看到这个数我就想到,应该是数据溢出了,因为int 4字节,32bit,其中有1位是符号位,那么int的范围应该是: -2147483648 ~2147483647
那int的时间戳,最多能算多少天后呢?
2147483647/1000/24/3600=24.85 ,那么,相当于用24天内的时间戳,是根本发现不了了,但是大于24天,就会出bug了。为了避免这种隐藏的bug,
那应该怎么避免这种问题呢?
超过2亿的整数运算,都不应该用int来做,而是应该用long来处理,所以时间戳的运算,都应该转成long运算,才不会出错。
if (addedProduct.getExpTime().getTime() > System.currentTimeMillis() + (long)30 * 24 * 3600 * 1000) {
// 只能提前30天续费
throw new CodeTipException(CodeTip.TIP_APPLY_PARAM_ERROR);
}
但是这样写是很不规范的,因为很容易忘记加上 long运算。
那么,我们应该用Calendar来处理,写成一个方法,这样就方便多了!
private static Date internalTrimOrAlterDate(
Date date,
boolean trim,
int dayDiff) {
if (null == date) {
return null;
}
Calendar cal = Calendar.getInstance();
cal.setTime(date);
if (trim) {
cal.set(Calendar.MILLISECOND, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.HOUR_OF_DAY, 0);
}
if (0 != dayDiff) {
cal.add(Calendar.DAY_OF_MONTH, dayDiff);
}
return cal.getTime();
}
其实这个问题的根源还是在于编码不规范,造成贪快一时爽,改bug火葬场,编码不规范,亲人两行泪!