如何获取PostgreSQL适配的日期极值解决JPA Criteria查询报错
解决JPA Criteria查询中PostgreSQL日期范围溢出问题
问题场景
我用JPA Criteria编写了文件过滤查询代码:
public class FileSpecification { public static Specification<FileEntity> getFilterdFiles(FilesFilterParams params) { return (root, query, criteriaBuilder) -> { List<Predicate> predicates = new ArrayList<>(); predicates.add(criteriaBuilder.between(root.get("uploadDate"), params.getUploadDateFrom() == null ? new Date(Long.MIN_VALUE) : params.getUploadDateFrom(), params.getUploadDateTo() == null ? new Date(Long.MAX_VALUE) : params.getUploadDateTo())); return criteriaBuilder.and(predicates.toArray(new Predicate[0])); }; } }
需求是当params.getUploadDateFrom()或params.getUploadDateTo()为null时,用最小/最大日期替代,但执行时触发PostgreSQL报错:
org.postgresql.util.PSQLException: ERROR: timestamp out of range: "292269055-12-02 21:47:04.192+05 BC"
原因是java.util.Date(Long.MIN_VALUE)和java.util.Date(Long.MAX_VALUE)超出了PostgreSQL的timestamp类型范围。我知道可以拆分谓词用criteriaBuilder.lessThanOrEqualTo/criteriaBuilder.greaterThanOrEqualTo解决,但想了解如何获取PostgreSQL兼容的正确日期极值。
解决方案
1. 使用PostgreSQL兼容的日期极值
PostgreSQL的timestamp类型支持的范围是公元前4713年1月1日到公元294276年12月31日,可以用以下方式构造对应Java日期:
方式一:兼容Java 8之前版本(用Calendar)
// 构造PostgreSQL支持的最小日期 Calendar minCal = Calendar.getInstance(); minCal.set(4713, Calendar.JANUARY, 1, 0, 0, 0); minCal.set(Calendar.MILLISECOND, 0); Date pgMinDate = minCal.getTime(); // 构造PostgreSQL支持的最大日期 Calendar maxCal = Calendar.getInstance(); maxCal.set(294276, Calendar.DECEMBER, 31, 23, 59, 59); maxCal.set(Calendar.MILLISECOND, 999); Date pgMaxDate = maxCal.getTime();
修改原代码的替换逻辑:
predicates.add(criteriaBuilder.between(root.get("uploadDate"), params.getUploadDateFrom() == null ? pgMinDate : params.getUploadDateFrom(), params.getUploadDateTo() == null ? pgMaxDate : params.getUploadDateTo()));
方式二:Java 8+版本(用Instant)
// 最小日期 Date pgMinDate = Date.from(Instant.parse("-4713-01-01T00:00:00Z")); // 最大日期 Date pgMaxDate = Date.from(Instant.parse("+294276-12-31T23:59:59.999Z"));
2. 更优雅的无边界条件写法(推荐)
不需要硬塞极值,直接根据参数是否为null动态添加谓词,数据库会自动匹配所有符合剩余条件的数据,既避免范围溢出,也减少不必要的范围判断:
public static Specification<FileEntity> getFilterdFiles(FilesFilterParams params) { return (root, query, criteriaBuilder) -> { List<Predicate> predicates = new ArrayList<>(); if (params.getUploadDateFrom() != null) { predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("uploadDate"), params.getUploadDateFrom())); } if (params.getUploadDateTo() != null) { predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("uploadDate"), params.getUploadDateTo())); } return criteriaBuilder.and(predicates.toArray(new Predicate[0])); }; }
内容的提问来源于stack exchange,提问作者Wythuk
相关产品推荐
相关产品推荐

