Java中日期比较返回-1异常:同日期比较也得-1的问题排查
看起来你遇到了java.sql.Date比较的经典时间戳坑,我来帮你拆解问题根源和解决办法:
为什么同日期比较会返回-1?
核心问题出在你创建currentDate的方式,以及java.sql.Date和java.util.Date的隐性差异:
时间戳的本质区别:
java.sql.Date是专门用于存储纯年月日的类型,它的时间戳会自动把时分秒、毫秒全部清零(比如2020-04-10对应的是当天00:00:00的毫秒数)。
而你代码里的new Date(new java.util.Date().getTime()),如果没有明确指定全类名,这里的Date大概率是java.util.Date——这个类型会包含当前完整的时间(比如2020-04-10 15:42:30的毫秒数)。compareTo的底层逻辑:
当你用数据库返回的java.sql.Date(0点时间戳)和currentDate(当天下午的时间戳)调用compareTo时,本质是比较两个时间戳的大小:0点的毫秒数必然小于当天下午的毫秒数,所以哪怕日期是同一天,也会返回-1,完全符合时间戳的比较逻辑。
另外你代码里还有个小细节:System.err.println("CAST= " +(Date) date);这里的强制转换如果是转成java.util.Date,虽然语法没问题,但会进一步加深类型混淆,没必要这么做。
修复方案
方案1:确保currentDate是纯年月日的java.sql.Date
把currentDate的创建改成明确的java.sql.Date,内部会自动清零时分秒:
// 直接用当前时间戳创建java.sql.Date,自动置零时分秒 java.sql.Date currentDate = new java.sql.Date(System.currentTimeMillis());
如果需要更精准的时区控制,可以用Calendar手动清零时间部分:
Calendar cal = Calendar.getInstance(); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); java.sql.Date currentDate = new java.sql.Date(cal.getTimeInMillis());
这样currentDate和数据库返回的java.sql.Date格式完全一致,同日期比较就会返回0了。
方案2:用Java 8+的LocalDate替代(推荐)
如果你的项目是Java 8及以上,强烈建议用java.time.LocalDate来处理纯日期逻辑,它天生只关注年月日,没有时间部分的坑,语义也更清晰:
try { String hql = "SELECT taskDate FROM TaskFutureDates t WHERE t.taskId= :taskId"; // Hibernate 5.2+支持直接将查询结果映射为LocalDate List<LocalDate> result = em.createQuery(hql, LocalDate.class) .setParameter("taskId", taskId) .getResultList(); LocalDate currentDate = LocalDate.now(); if (!result.isEmpty()) { for(LocalDate date: result) { // 用isEqual和isAfter替代compareTo,语义更直观 if(date.isEqual(currentDate) || date.isAfter(currentDate)) { System.err.println("DATE= " + date); return Date.valueOf(date); // 如需返回java.sql.Date,直接转换即可 } } } } catch (Exception e) { e.printStackTrace(); // 建议不要注释掉异常打印,方便排查问题 } return null;
额外小建议
- 检查代码的导入语句,避免
java.util.Date和java.sql.Date的混淆,必要时用全类名指定 - 代码里的
: taskId有个多余的空格,虽然HQL可能兼容,但写成:taskId更规范 - 不要忽略异常处理,打印异常栈信息能帮你快速定位后续的潜在问题
内容的提问来源于stack exchange,提问作者sagar

