最简单安全的方式是将Date和Calendar统一转为毫秒时间戳比较:Date用getTime(),Calendar用getTimeInMillis(),二者均返回自1970-01-01 UTC起的毫秒数,可直接比大小;应封装为null安全的工具方法,推荐迁移到java.time体系。

直接将 Date 和 Calendar 统一转为毫秒时间戳再比较,是最简单、安全且兼容性最好的方式。
统一转为 long 时间戳比较
Date 本身有 getTime() 方法返回自 1970-01-01 00:00:00 UTC 起的毫秒数;Calendar 可通过 getTimeInMillis() 获取等效值。两者本质都是毫秒级时间表示,可直接比大小。
- 避免类型强转或 instanceof 判断,减少逻辑分支
- 不依赖时区细节——只要原始 Calendar 的时区已设定好,
getTimeInMillis()就已反映其真实时刻 - 示例写法:
Comparator<Object> timeComparator = (o1, o2) -> {
long t1 = (o1 instanceof Date) ? ((Date) o1).getTime() :
(o1 instanceof Calendar) ? ((Calendar) o1).getTimeInMillis() : 0L;
long t2 = (o2 instanceof Date) ? ((Date) o2).getTime() :
(o2 instanceof Calendar) ? ((Calendar) o2).getTimeInMillis() : 0L;
return Long.compare(t1, t2);
};
封装成泛型工具方法更安全
硬写 instanceof 容易出错,建议提取为可复用的工具函数,支持 null 安全和类型校验。
- 对 null 值约定统一排在前面或后面(例如 null 视为最小)
- 非 Date/Calendar 类型抛 IllegalArgumentException,避免静默失败
- 示例:
public static long toMillis(Object timeObj) {
if (timeObj == null) return Long.MIN_VALUE; // 或 MAX_VALUE,按需
if (timeObj instanceof Date) return ((Date) timeObj).getTime();
if (timeObj instanceof Calendar) return ((Calendar) timeObj).getTimeInMillis();
throw new IllegalArgumentException("Unsupported time type: " + timeObj.getClass());
}
Comparator<Object> safeTimeComparator = Comparator.comparing(Main::toMillis);
推荐升级到 java.time(长期维护角度)
如果项目允许,应逐步迁移到 java.time 体系(如 Instant、ZonedDateTime),它天然统一、不可变、线程安全。
立即学习“Java免费学习笔记(深入)”;
-
Date→date.toInstant() -
Calendar→calendar.toInstant() - 所有时间对象都可转为
Instant,再用Instant.compareTo()排序 - 这样既解耦旧 API,又为未来清理打下基础
注意 Calendar 的时区陷阱
Calendar 是可变对象,且自带时区信息。同一个毫秒值,在不同时区下 get(...) 结果不同,但 getTimeInMillis() 始终返回 UTC 毫秒数,是唯一可靠依据。
- 不要用
calendar.get(Calendar.YEAR)等字段做排序——结果依赖当前时区 - 确保 Calendar 实例已调用
setTime(...)或明确初始化,否则可能含默认值 - 若需按“本地日历日期”排序(如只看年月日),应先截断时分秒再比较,而非直接用毫秒


















