核心概念

  1. 时间单位
    • 1 天 = 24 小时
    • 1 小时 = 3,600 秒
    • 1 秒 = 1,000 毫秒
  2. Date 本质:存储自 1970-01-01 00:00:00 UTC 起的毫秒数(时间戳)
  3. 计算原理:差值 = 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);

常见错误

  1. 整数溢出

    int diff = (int) (date1.getTime() - date2.getTime()); // 可能溢出
    

    修复:始终使用 long 存储差值

  2. 时区忽略

    Date date = new Date(2023, 1, 1); // 使用系统默认时区
    

    现象:不同时区用户计算结果不同

  3. 精度丢失

    double days = diffMillis / 86400000; // 整数除法丢失小数
    

    修复

    double days = (double) diffMillis / 86_400_000;
    

注意事项

  1. 夏令时影响24 小时 ≠ 1 天(夏令时切换日)

    // 夏令时切换日计算可能差1小时
    TimeZone.setDefault(TimeZone.getTimeZone("America/New_York"));
    
  2. 闰秒问题:Java 忽略闰秒,UTC-SLS 处理

  3. 日期边界

    // 2023-03-12 02:30 可能不存在(夏令时)
    new Date(123, 2, 12, 2, 30); // 自动变为 03:30
    

使用技巧

  1. 精确时间差

    double exactHours = diffMillis / 3_600_000.0;
    
  2. 时间段格式化

    String.format("%d天%d小时", days, remainingHours);
    
  3. 比较前对齐时区

    long utc1 = date1.getTime() + TimeZone.getDefault().getOffset(date1.getTime());
    

最佳实践 & 性能优化

  1. 优先使用 Java 8+ 的 Time API

    Duration duration = Duration.between(
        date1.toInstant(), 
        date2.toInstant()
    );
    long hours = duration.toHours();
    
  2. 缓存时间戳

    // 避免多次调用 getTime()
    final long ts1 = date1.getTime();
    final long ts2 = date2.getTime();
    
  3. 常量优化

    private static final long MILLIS_PER_HOUR = 60 * 60 * 1000;
    long hours = diffMillis / MILLIS_PER_HOUR;
    
  4. 时区处理

    // 统一转换为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() + "天");
    }
}