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

Java 計算兩日期相差天數的正確姿勢

     編輯:Java 相關知識

日期差值計算的常見陷阱與最佳實踐

在 Java 中計算兩個日期相差的天數看似簡單,實則暗藏時區、夏令時間、閏年等陷阱。本文分析常見錯誤做法,提供正確且健壯的解決方案。

錯誤示範:毫秒數直接相除

許多初學者直接使用毫秒差值除以一天的毫秒數:

// ❌ 錯誤做法
long diff = date2.getTime() - date1.getTime();
long days = diff / (24 * 60 * 60 * 1000);

致命缺陷:忽略夏令時間切換導致某天非 24 小時、跨時區計算偏差、閏秒影響。

正確做法一:Calendar API(Java 7 及之前)

利用 Calendar.DAY_OF_YEAR 與年份差值計算:

public static int getDaysBetween(Date date1, Date date2) {
    Calendar cal1 = Calendar.getInstance();
    Calendar cal2 = Calendar.getInstance();
    cal1.setTime(date1);
    cal2.setTime(date2);

    int days = cal2.get(Calendar.DAY_OF_YEAR) - cal1.get(Calendar.DAY_OF_YEAR);
    int year2 = cal2.get(Calendar.YEAR);

    if (cal1.get(Calendar.YEAR) != year2) {
        Calendar temp = (Calendar) cal1.clone();
        do {
            days += temp.getActualMaximum(Calendar.DAY_OF_YEAR);
            temp.add(Calendar.YEAR, 1);
        } while (temp.get(Calendar.YEAR) != year2);
    }
    return days;
}

優點:正確處理跨年、閏年。
缺點:Calendar 可變性差、API 繁瑣、時區處理易出錯。

正確做法二:Java 8+ 新日期時間 API(推薦)

java.time 套件提供不可變、執行緒安全的日期類別:

import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Date;

public static long daysBetween(Date date1, Date date2) {
    LocalDate ld1 = date1.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    LocalDate ld2 = date2.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    return ChronoUnit.DAYS.between(ld1, ld2);
}

核心優勢:

  • LocalDate 只有日期無時間,天然適合「天數差」計算
  • ChronoUnit.DAYS.between 內建處理閏年、月份長短
  • 不可變物件,執行緒安全
  • 支援時區明確轉換

進階場景處理

指定時區計算

// 以紐約時區為準計算天數差
ZoneId ny = ZoneId.of("America/New_York");
LocalDate ld1 = date1.toInstant().atZone(ny).toLocalDate();
LocalDate ld2 = date2.toInstant().atZone(ny).toLocalDate();

包含起始日/結束日的邏輯


// 含首尾日:+1
long inclusiveDays = ChronoUnit.DAYS.between(start, end) + 1;

// 僅計算完整 24 小時週期
long fullDays = ChronoUnit.DAYS.between(start.atStartOfDay(), end.atStartOfDay());

效能比較與選擇建議

方案適用版本執行緒安全可讀性推薦指數
毫秒相除所有版本是高⭐ (錯誤)
CalendarJava 1.1+否低⭐⭐
java.timeJava 8+是高⭐⭐⭐⭐⭐

總結

專案若使用 Java 8 或更新版本,首選 java.time.LocalDate 與 ChronoUnit。舊版專案可使用 Calendar 方案,但需謹慎處理時區與可變性問題。切勿使用毫秒相除的簡易做法,除非業務極其簡單且能容忍誤差。

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