給定兩個日期時間,計算差值並格式化為「X天X小時X分X秒」。
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TimeDiffLegacy {
public static void main(String[] args) {
String startStr = "2004-01-02 11:30:24";
String endStr = "2004-03-26 13:31:40";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
Date start = sdf.parse(startStr);
Date end = sdf.parse(endStr);
long diffMs = end.getTime() - start.getTime(); // 毫秒差
printDiff(diffMs);
} catch (ParseException e) {
e.printStackTrace();
}
}
private static void printDiff(long diffMs) {
long seconds = diffMs / 1000;
long days = seconds / (24 * 3600);
long hours = (seconds % (24 * 3600)) / 3600;
long minutes = (seconds % 3600) / 60;
long secs = seconds % 60;
System.out.printf("差值:%d天 %d小時 %d分 %d秒%n", days, hours, minutes, secs);
// 輸出:差值:83天 2小時 1分 16秒
}
}
import java.util.Calendar;
import java.util.Date;
public class TimeDiffCalendar {
public static void main(String[] args) {
Calendar start = Calendar.getInstance();
start.set(2004, Calendar.JANUARY, 2, 11, 30, 24); // 月份 0-based
Calendar end = Calendar.getInstance();
end.set(2004, Calendar.MARCH, 26, 13, 31, 40);
long diffMs = end.getTimeInMillis() - start.getTimeInMillis();
// 同方法一計算天/時/分/秒
}
}
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
public class TimeDiffModern {
public static void main(String[] args) {
String startStr = "2004-01-02 11:30:24";
String endStr = "2004-03-26 13:31:40";
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime start = LocalDateTime.parse(startStr, fmt);
LocalDateTime end = LocalDateTime.parse(endStr, fmt);
// 1. 總差值各單位
long days = ChronoUnit.DAYS.between(start, end);
long hours = ChronoUnit.HOURS.between(start, end) % 24;
long minutes = ChronoUnit.MINUTES.between(start, end) % 60;
long seconds = ChronoUnit.SECONDS.between(start, end) % 60;
System.out.printf("差值:%d天 %d小時 %d分 %d秒%n", days, hours, minutes, seconds);
// 2. Duration 物件完整資訊
java.time.Duration duration = java.time.Duration.between(start, end);
System.out.println("總毫秒:" + duration.toMillis());
System.out.println("總秒數:" + duration.getSeconds());
System.out.println("標準格式:" + duration); // PT83H2M1.16S (ISO-8601)
// 3. Period 用於日期差(年/月/日)
java.time.Period period = java.time.Period.between(start.toLocalDate(), end.toLocalDate());
System.out.printf("日期差:%d年 %d月 %d日%n", period.getYears(), period.getMonths(), period.getDays());
}
}
| 維度 | Date.getTime() | Calendar | java.time (JDK 8+) |
|---|---|---|---|
| API 設計 | 簡單、偏向機器 | 繁瑣、可變、月份 0-based | 流暢、不可變、領域模型清晰 |
| 執行緒安全 | Date 可變,不安全 | Calendar 可變,不安全 | 不可變,天然安全 |
| 時區處理 | 隱含系統預設 | 隱含系統預設 | 顯式 ZoneId/ZonedDateTime |
| 解析/格式化 | SimpleDateFormat (不安全) | 同左 | DateTimeFormatter (安全) |
| 差值計算 | 手動毫秒換算 | 手動毫秒換算 | ChronoUnit / Duration / Period 內建 |
| 跨夏令時正確性 | 易錯 | 易錯 | ZonedDateTime 正確處理 |
// 跨時區:使用 ZonedDateTime
ZoneId taipei = ZoneId.of("Asia/Taipei");
ZoneId ny = ZoneId.of("America/New_York");
ZonedDateTime start = ZonedDateTime.of(2024, 3, 10, 12, 0, 0, 0, taipei);
ZonedDateTime end = ZonedDateTime.of(2024, 3, 10, 20, 0, 0, 0, ny);
Duration d = Duration.between(start, end); // 自動處理時區差與夏令時
// 僅計算工作日(排除週末、假日)— 需自行實作或用三方庫
// 推薦:ThreeTen-Extra (LocalDateRange, BusinessDay) 或 Joda-Time 遺產
ThreadLocal,或升級 DateTimeFormatter。Calendar.JANUARY = 0,LocalDateTime 月份 1-based。Duration.between 計算物理時間差,Period 計算日曆日期差,業務語意不同。int 儲存天數可能溢位,用 long。Date.getTime() 毫秒換算邏輯。Duration、Period、ChronoUnit 內建方法,程式碼更清晰、安全、正確。Duration.format() (JDK 9+) 自定義格式化。