如何通过CriteriaQuery从timestamp列中查询指定日期的数据?
问题根源
数据库的timestamp字段包含完整的年月日时分秒信息,你通过SimpleDateFormat解析2023-07-27得到的Date对象是当天的00:00:00,只有当数据库中createdAt的时间恰好等于这个时刻时,equal才会匹配,自然查不到当天其他时间点的数据。
解决方案
这里提供两种可靠的实现方式:
方案1:查询当天完整时间范围
构造当天的起始时间(00:00:00)和结束时间(23:59:59.999),通过between做范围匹配:
List<Predicate> predicates = new ArrayList<>(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); Date startDateObj = dateFormat.parse(startDate); // 计算当天结束时间:起始日期加1天,再减1毫秒 Calendar calendar = Calendar.getInstance(); calendar.setTime(startDateObj); calendar.add(Calendar.DAY_OF_MONTH, 1); calendar.add(Calendar.MILLISECOND, -1); Date endDateObj = calendar.getTime(); if (request.getKey().equals("createdAt")) { predicates.add(criteriaBuilder.between(root.get("createdAt"), startDateObj, endDateObj)); }
方案2:提取日期部分直接比较
利用JPA的函数调用,提取createdAt的日期部分和目标日期对比(不同数据库函数略有差异):
List<Predicate> predicates = new ArrayList<>(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); Date targetDate = dateFormat.parse(startDate); if (request.getKey().equals("createdAt")) { // MySQL 环境:用DATE()函数提取日期部分 Expression<String> createdAtDate = criteriaBuilder.function( "DATE", String.class, root.get("createdAt") ); String targetDateStr = dateFormat.format(targetDate); predicates.add(criteriaBuilder.equal(createdAtDate, targetDateStr)); // PostgreSQL 环境:改用DATE_TRUNC()函数 // Expression<Date> createdAtDate = criteriaBuilder.function( // "DATE_TRUNC", // Date.class, // criteriaBuilder.literal("day"), // root.get("createdAt") // ); // predicates.add(criteriaBuilder.equal(createdAtDate, targetDate)); }
额外建议
- 优先使用Java 8+的
DateTimeFormatter替代SimpleDateFormat,后者线程不安全:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); LocalDate targetLocalDate = LocalDate.parse(startDate, formatter); // 转换为java.util.Date(如果需要适配旧代码) Date targetDate = Date.from(targetLocalDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
- 确认应用服务器和数据库的时区一致,避免时间转换导致的匹配偏差。
内容的提问来源于stack exchange,提问作者Amanuel Zerfu
相关产品推荐
相关产品推荐

