我为这个奇怪的问题苦苦挣扎了一整天。问题是这样的:
下面有三行代码
float y=Float.parseFloat(line[1]);
int dayDiff = DateUtil.countDay(lineDateid,testDateIdBelongTo,true);//
dataBelongTo.set(dayDiff,y);// Some error thrown from here, so I set a break point here and watch
我在第三行发现了一些奇怪的 IndexOutOfBound Exception,所以我开始调试(断点条件为 (dayDiff<0) || (dayDiff>=dataBelongTo.size())
)并注意到奇怪的结果,下面是屏幕截图:
我注意到 dayDiff 返回了意外的结果,并且 DateUtil.countDay
似乎返回不一致的结果,所以我在主方法中调试它:
try {
System.out.println("begins");
for(int i=0; i< 500000;i++){//run 500000 times
int dateDiff = DateUtil.countDay(20150604,20150601,true);
if(dateDiff!=3) System.out.println(dateDiff);
}
System.out.println("ends");
} catch (Exception e) {
e.printStackTrace();
}
但是结果是对的!每次都返回3(没有错误结果打印)!!
这是我的代码 countDay
public static int countDay(int day1, int day2 , boolean distinguish ) {
int res = 0;
try {
Date date1 = formatDate.parse(day1+"");
Date date2 = formatDate.parse(day2 + "");
long diff = date1.getTime() - date2.getTime();
res = (int)TimeUnit.MILLISECONDS.toDays(diff);
} catch (ParseException e) {
e.printStackTrace();
}
if(!distinguish)
res =Math.abs(res);
return res;
}
和formatDate
是
public static final SimpleDateFormat formatDate = new SimpleDateFormat("yyyyMMdd");
PS:我使用的是 JDK 7,问题代码在 Tomcat 上运行,数据(param)来自 MySQL 。
这是该问题部分的更完整代码,仅在某些情况下才会出现问题。
for(String[] line : tableData){//for each records in the database
int lineDateid = Integer.parseInt(line[0]);//0 index is dateid
int testDateIdBelongTo = 0;//init with 0
JSONArray dataBelongTo = null;//data array
//below , need to assgin dataBelongTo and testDateIdBelongTo
for(int i=0;i<testDates.length;i++){
int testDate =testDates[i];
NumberInterval interval = intervals.get(i);
if(interval.isIn(lineDateid)){
dataBelongTo = datas.get(i);
testDateIdBelongTo=testDate;
break;
}
}
if(testDateIdBelongTo==0) throw new IllegalStateException("data errors, no matched dataid");
float y=Float.parseFloat(line[1]);
int dayDiff = DateUtil.countDay(lineDateid,testDateIdBelongTo,true);
dataBelongTo.set(dayDiff,y);
}
最佳答案
最可能的原因是:
public static final SimpleDateFormat formatDate = new SimpleDateFormat("yyyyMMdd");
SimpleDateFormat
不是线程安全的,Tomcat 可能从多个线程调用此单个实例。
简单修复:删除静态变量并更改代码:
public static int countDay(int day1, int day2 , boolean distinguish ) {
SimpleDateFormat formatDate = new SimpleDateFormat("yyyyMMdd");
//rest of your code
}
如果性能是一个问题,您可以缓存格式化程序,但这将使代码变得更加复杂(正如注释中所述,在管理自己的线程池的应用程序服务器中可能不建议使用 ThreadLocals 的典型方法)。
您还可以重写代码以不使用 SimpleDateFormat - 这可能会更简单。
顺便说一句,如果运行代码的计算机的默认时区发生 DST 更改,您当前的计算可能会被破坏。
关于java - 按 yyyymmdd 整数计算日差时结果不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30663316/