核心概念
- 时间单位:
- 1 天 = 24 小时
- 1 小时 = 3,600 秒
- 1 秒 = 1,000 毫秒
- Date 本质:存储自 1970-01-01 00:00:00 UTC 起的毫秒数(时间戳)
- 计算原理:差值 =
date1.getTime() - date2.getTime()
(毫秒)
详细操作步骤
步骤 1:获取时间戳
Date date1 = new Date();
Date date2 = new Date(System.currentTimeMillis() - 86_400_000); // 昨天
long timestamp1 = date1.getTime();
long timestamp2 = date2.getTime();
步骤 2:计算毫秒差值
long diffMillis = Math.abs(timestamp1 - timestamp2); // 取绝对值
步骤 3:转换为目标单位
// 转换为秒
long diffSeconds = diffMillis / 1000;
// 转换为分钟
long diffMinutes = diffMillis / (1000 * 60);
// 转换为小时
long diffHours = diffMillis / (1000 * 60 * 60);
// 转换为天
long diffDays = diffMillis / (1000 * 60 * 60 * 24);
// 精确天+小时(带余数)
long days = diffMillis / (1000 * 60 * 60 * 24);
long remainingHours = (diffMillis % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60);
常见错误
整数溢出:
int diff = (int) (date1.getTime() - date2.getTime()); // 可能溢出
修复:始终使用
long
存储差值时区忽略:
Date date = new Date(2023, 1, 1); // 使用系统默认时区
现象:不同时区用户计算结果不同
精度丢失:
double days = diffMillis / 86400000; // 整数除法丢失小数
修复:
double days = (double) diffMillis / 86_400_000;
注意事项
夏令时影响:
24 小时 ≠ 1 天
(夏令时切换日)// 夏令时切换日计算可能差1小时 TimeZone.setDefault(TimeZone.getTimeZone("America/New_York"));
闰秒问题:Java 忽略闰秒,UTC-SLS 处理
日期边界:
// 2023-03-12 02:30 可能不存在(夏令时) new Date(123, 2, 12, 2, 30); // 自动变为 03:30
使用技巧
精确时间差:
double exactHours = diffMillis / 3_600_000.0;
时间段格式化:
String.format("%d天%d小时", days, remainingHours);
比较前对齐时区:
long utc1 = date1.getTime() + TimeZone.getDefault().getOffset(date1.getTime());
最佳实践 & 性能优化
优先使用 Java 8+ 的 Time API:
Duration duration = Duration.between( date1.toInstant(), date2.toInstant() ); long hours = duration.toHours();
缓存时间戳:
// 避免多次调用 getTime() final long ts1 = date1.getTime(); final long ts2 = date2.getTime();
常量优化:
private static final long MILLIS_PER_HOUR = 60 * 60 * 1000; long hours = diffMillis / MILLIS_PER_HOUR;
时区处理:
// 统一转换为UTC计算 long utcMillis1 = date1.getTime() - TimeZone.getDefault().getRawOffset();
完整示例代码
import java.util.*;
import java.time.Duration;
public class DateDiffCalculator {
private static final long MILLIS_PER_DAY = 86_400_000;
private static final long MILLIS_PER_HOUR = 3_600_000;
public static void main(String[] args) {
// 创建两个日期(今天和昨天此时)
Date now = new Date();
Date yesterday = new Date(System.currentTimeMillis() - MILLIS_PER_DAY + MILLIS_PER_HOUR * 2);
// 计算差值
printTimeDiff(now, yesterday);
}
public static void printTimeDiff(Date d1, Date d2) {
// 1. 获取时间戳
long ts1 = d1.getTime();
long ts2 = d2.getTime();
// 2. 计算绝对差值
long diff = Math.abs(ts1 - ts2);
// 3. 转换单位
long days = diff / MILLIS_PER_DAY;
long hours = (diff % MILLIS_PER_DAY) / MILLIS_PER_HOUR;
// 4. 判断先后
String relation = (ts1 > ts2) ? "之后" : "之前";
System.out.printf("日期1: %s\n日期2: %s\n", d1, d2);
System.out.printf("相差: %d 天 %d 小时 (%s)\n", days, hours, relation);
// 使用Java 8 API验证
Duration dur = Duration.between(d1.toInstant(), d2.toInstant());
System.out.println("Duration验证: " + dur.abs().toDays() + "天");
}
}