首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java 計算兩個日期相差天數的多種實現方案

     編輯:Java 程式設計入門

在業務開發中,計算兩個日期之間的天數差是高頻需求(如物流時效、租賃到期、會員剩餘天數等)。本文整理了從 JDK 原生 API 到第三方庫的多種實現方式,並分析其優缺點,助你根據場景選擇最優方案。

方案一:Calendar 手動計算(兼容舊版本 JDK)

適用於 JDK 7 及以下環境,邏輯較繁瑣,需手動處理跨年、閏年情況。

public static int dateInterval(long date1, long date2) {
    // 確保 date1 >= date2,保證結果為正數
    if (date2 > date1) { /* 交換邏輯 */ }

    Calendar cal1 = Calendar.getInstance();
    cal1.setTimeInMillis(date1);
    Calendar cal2 = Calendar.getInstance();
    cal2.setTimeInMillis(date2);

    int y1 = cal1.get(Calendar.YEAR);
    int y2 = cal2.get(Calendar.YEAR);
    int d1 = cal1.get(Calendar.DAY_OF_YEAR);
    int d2 = cal2.get(Calendar.DAY_OF_YEAR);

    if (y1 == y2) {
        return d1 - d2; // 同年直接相減
    }
    // 跨年需累加中間整年的天數(含閏年判斷)
    return calculateCrossYearDays(d1, d2, y1, y2, cal2);
}

缺點:代碼量大、易出錯、需自行處理閏年與跨年邏輯。

方案二:SimpleDateFormat + 毫秒差值(簡單但有陷阱)

將日期轉為毫秒時間戳,相減後除以一天的毫秒數。

public static int daysBetween(Date d1, Date d2) {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    // 關鍵:格式化後再解析,將時分秒歸零,避免時間差導致天數誤差
    d1 = sdf.parse(sdf.format(d1));
    d2 = sdf.parse(sdf.format(d2));

    long diff = d2.getTime() - d1.getTime();
    return (int) (diff / (1000 * 60 * 60 * 24));
}

注意:必須將時分秒歸零,否則「2023-01-01 23:00」到「2023-01-02 01:00」僅 2 小時,卻會被算作 1 天差。

方案三:GregorianCalendar 逐日疊加(精確但效率低)

利用 Calendar.add(Calendar.DATE, 1) 逐日遞增計數,絕對精確但大跨度日期性能差。

public int getDays(GregorianCalendar g1, GregorianCalendar g2) {
    // 清除時分秒毫秒,確保按「日」比較
    clearTimeFields(g1); clearTimeFields(g2);
    int elapsed = 0;
    while (g1.before(g2)) {
        g1.add(Calendar.DATE, 1);
        elapsed++;
    }
    return elapsed;
}

方案四:Joda-Time(JDK 8 前的最佳選擇)

語義清晰、API 豐富、處理時區/閏年極其可靠。

// 判斷租賃是否超期(2天期限)
public boolean isRentalOverdue(DateTime rented) {
    return rented.plus(Period.days(2)).isBeforeNow();
}

方案五:Java 8+ 新日期時間 API(現代標準)

強烈推薦:java.time 包不可變、線程安全、API 直觀。

// LocalDate 適合無時間、無時區的日期計算
long days = ChronoUnit.DAYS.between(
    LocalDate.parse("2023-01-01"),
    LocalDate.parse("2023-01-10")
); // 返回 9

// 或使用 Period 獲取年/月/日差
Period p = Period.between(startDate, endDate);
int totalDays = p.getDays() + p.getMonths() * 30 + p.getYears() * 365; // 近似

方案對比與選型建議

方案適用場景優點缺點
Calendar 手算JDK 7 維護老項目無依賴代碼複雜、易錯
毫秒差值法簡單快速原型、同時區代碼極短需手動歸零時間、跨 DST 可能誤差
逐日疊加極高精度要求、小跨度絕對精確大跨度性能極差
Joda-TimeJDK 8 前新項目功能強大、業界標準需引入第三方依賴
Java 8 java.time所有新項目首選標準庫、不可變、線程安全、API 現代需 JDK 8+

最佳實踐總結

  1. 新項目:直接使用 java.time.LocalDate + ChronoUnit.DAYS.between(),一行代碼解決。
  2. 舊項目維護:若已引入 Joda-Time 繼續用;否則用毫秒差值法並務必歸零時間。
  3. 避免在業務代碼中手寫閏年/跨年邏輯,極易產生難以復現的 Bug。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved