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

Java 計算兩日期間隔天數工具類:基於 Calendar 避開時區與夏令時陷阱

     編輯:Java 相關知識

Java 計算兩日期間隔天數工具類:基於 Calendar 避開時區與夏令時陷阱

直接用 Date.getTime() 相減除以 24*3600*1000 會在夏令時切換日產生誤差。正確做法:使用 Calendar 的 DAY_OF_YEAR 與 YEAR 欄位,逐年累加每年實際天數(getActualMaximum(DAY_OF_YEAR)),實現**與 Calendar 實現無關、無視時區/夏令時**的精確天數差。附生產級工具方法代碼。

核心算法邏輯

  1. 確保 d1 ≤ d2(否則交換)。
  2. 同年:直接用 d2.DAY_OF_YEAR - d1.DAY_OF_YEAR。
  3. 跨年:d1 逐年 add(YEAR, 1) 累加 getActualMaximum(DAY_OF_YEAR),直到年份追上 d2,再加上同年差值。
  4. 返回非負整數,相同日期返回 0,相鄰返回 1。

完整工具方法(可直接複製到項目)


/**
 * 計算兩個 Calendar 日期之間的天數差(忽略時間分量)。
 * @param d1 起始日期
 * @param d2 結束日期
 * @return 天數差,>=0。順序不影響結果。
 * @throws IllegalArgumentException 若傳入 null
 */
public static int getDaysBetween(java.util.Calendar d1, java.util.Calendar d2) {
    if (d1 == null || d2 == null) throw new IllegalArgumentException("Calendar 參數不能為 null");
    // 確保 d1 <= d2
    if (d1.after(d2)) {
        java.util.Calendar tmp = d1; d1 = d2; d2 = tmp;
    }
    int days = d2.get(java.util.Calendar.DAY_OF_YEAR) - d1.get(java.util.Calendar.DAY_OF_YEAR);
    int y2 = d2.get(java.util.Calendar.YEAR);
    if (d1.get(java.util.Calendar.YEAR) != y2) {
        d1 = (java.util.Calendar) d1.clone(); // 不修改原對象
        do {
            days += d1.getActualMaximum(java.util.Calendar.DAY_OF_YEAR);
            d1.add(java.util.Calendar.YEAR, 1);
        } while (d1.get(java.util.Calendar.YEAR) != y2);
    }
    return days;
}

關鍵設計細節

細節作用
d1.clone()避免修改呼叫端傳入的 Calendar 實例(副作用預防)。
getActualMaximum(DAY_OF_YEAR)自動處理閏年(366 天)與平年(365 天),無需硬編碼判斷邏輯。
僅比較 DAY_OF_YEAR + YEAR忽略 HOUR_OF_DAY、MINUTE 等時間分量,專注「日期」差。
拋檢 null防禦性編程,早失敗易排查。

使用範例


Calendar c1 = Calendar.getInstance(); c1.set(2024, Calendar.FEBRUARY, 28); // 2024-02-28
Calendar c2 = Calendar.getInstance(); c2.set(2024, Calendar.MARCH, 1);     // 2024-03-01
System.out.println(getDaysBetween(c1, c2)); // 輸出 2 (閏年 2/29 存在)

Calendar c3 = Calendar.getInstance(); c3.set(2023, Calendar.FEBRUARY, 28);
Calendar c4 = Calendar.getInstance(); c4.set(2023, Calendar.MARCH, 1);
System.out.println(getDaysBetween(c3, c4)); // 輸出 1 (平年無 2/29)

常見誤區對比

錯誤做法問題正確做法
(d2.getTimeInMillis() - d1.getTimeInMillis()) / (24*3600*1000)夏令時切換日相差 23/25 小時,導致天數誤差 ±1使用 Calendar 欄位運算(本文方法)
SimpleDateFormat.parse() 後相減同樣受時區/夏令時影響,且格式解析效能低直接構造 Calendar 或用 LocalDate (Java 8+)
手寫閏年判斷易漏邊界、代碼冗餘getActualMaximum(DAY_OF_YEAR) 一行搞定

Java 8+ 現代替代


// Java 8+ 推薦:LocalDate 天生無時區、不可變、API 簡潔
public static long daysBetween(java.time.LocalDate d1, java.time.LocalDate d2) {
    return Math.abs(java.time.temporal.ChronoUnit.DAYS.between(d1, d2));
}

舊專案維護期繼續用 Calendar 版本;新專案**首選 java.time 包**。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved