Java Duration 和 Period
Duration 用於表示以秒和奈秒為單位的時間間隔,而 Period 用於表示以年、月、日為單位的日期間隔。
Duration(時間間隔)
適用於時間點之間的精確時間差:
import java.time.Duration;
import java.time.LocalTime;
import java.time.LocalDateTime;
import java.time.Instant;
// 計算兩個時間之間的差距
LocalTime start = LocalTime.of(9, 0);
LocalTime end = LocalTime.of(17, 30);
Duration duration = Duration.between(start, end);
System.out.println(duration); // PT8H30M
System.out.println(duration.toHours()); // 8
System.out.println(duration.toMinutes()); // 510
System.out.println(duration.getSeconds()); // 30600
建立 Duration
// 從時間單位建立
Duration hours = Duration.ofHours(5); // PT5H
Duration minutes = Duration.ofMinutes(30); // PT30M
Duration seconds = Duration.ofSeconds(90); // PT1M30S
Duration millis = Duration.ofMillis(1500); // PT1.5S
Duration nanos = Duration.ofNanos(1000000); // PT0.001S
// 從字串解析
Duration parsed = Duration.parse("PT2H30M"); // 2 小時 30 分鐘
// 組合
Duration combined = Duration.ofHours(2).plusMinutes(30); // PT2H30M
Duration 運算
Duration duration = Duration.ofHours(5);
// 加減運算
Duration plus = duration.plusMinutes(30); // PT5H30M
Duration minus = duration.minusHours(1); // PT4H
// 乘除運算
Duration doubled = duration.multipliedBy(2); // PT10H
Duration halved = duration.dividedBy(2); // PT2H30M
// 絕對值
Duration negative = Duration.ofHours(-5);
Duration absolute = negative.abs(); // PT5H
// 取反
Duration negated = duration.negated(); // PT-5H
取得 Duration 資訊
Duration duration = Duration.ofHours(2).plusMinutes(30).plusSeconds(45);
// 各種單位
duration.toDays(); // 0
duration.toHours(); // 2
duration.toMinutes(); // 150
duration.toSeconds(); // 9045
duration.toMillis(); // 9045000
duration.toNanos(); // 9045000000000
// 取得部分
duration.toHoursPart(); // 2
duration.toMinutesPart(); // 30
duration.toSecondsPart(); // 45
// 檢查
duration.isZero(); // false
duration.isNegative(); // false
Duration 應用
// 計算執行時間
Instant start = Instant.now();
// ... 執行任務 ...
Instant end = Instant.now();
Duration elapsed = Duration.between(start, end);
System.out.println("執行時間:" + elapsed.toMillis() + " 毫秒");
// 設定超時
Duration timeout = Duration.ofSeconds(30);
if (waitTime.compareTo(timeout) > 0) {
throw new TimeoutException("操作超時");
}
// 格式化輸出
public String formatDuration(Duration d) {
long hours = d.toHours();
int minutes = d.toMinutesPart();
int seconds = d.toSecondsPart();
return String.format("%d:%02d:%02d", hours, minutes, seconds);
}
Period(日期間隔)
適用於日期之間以年月日計算的差距:
import java.time.Period;
import java.time.LocalDate;
// 計算兩個日期之間的差距
LocalDate start = LocalDate.of(2020, 1, 1);
LocalDate end = LocalDate.of(2024, 12, 10);
Period period = Period.between(start, end);
System.out.println(period); // P4Y11M9D
System.out.println(period.getYears()); // 4
System.out.println(period.getMonths()); // 11
System.out.println(period.getDays()); // 9
建立 Period
// 從日期單位建立
Period years = Period.ofYears(2); // P2Y
Period months = Period.ofMonths(6); // P6M
Period weeks = Period.ofWeeks(4); // P28D(轉換為天)
Period days = Period.ofDays(10); // P10D
// 組合
Period combined = Period.of(1, 6, 15); // 1年6個月15天
// 從字串解析
Period parsed = Period.parse("P1Y6M15D");
Period 運算
Period period = Period.of(1, 6, 15);
// 加減運算
Period plus = period.plusMonths(3); // P1Y9M15D
Period minus = period.minusDays(5); // P1Y6M10D
// 乘法
Period doubled = period.multipliedBy(2); // P2Y12M30D
// 取反
Period negated = period.negated(); // P-1Y-6M-15D
// 標準化(只調整月和年)
Period normalized = Period.of(0, 15, 0).normalized(); // P1Y3M
取得 Period 資訊
Period period = Period.of(2, 8, 15);
// 各部分
period.getYears(); // 2
period.getMonths(); // 8
period.getDays(); // 15
// 總天數(近似值)
period.toTotalMonths(); // 32
// 檢查
period.isZero(); // false
period.isNegative(); // false(任一部分為負則為 true)
Period 應用
// 計算年齡
public int calculateAge(LocalDate birthday) {
LocalDate today = LocalDate.now();
Period age = Period.between(birthday, today);
return age.getYears();
}
// 計算到期日
public LocalDate calculateDueDate(LocalDate startDate, Period validity) {
return startDate.plus(validity);
}
// 會員有效期
Period membershipPeriod = Period.ofYears(1);
LocalDate expiryDate = LocalDate.now().plus(membershipPeriod);
Duration vs Period
| 特性 | Duration | Period |
|---|---|---|
| 單位 | 秒、奈秒 | 年、月、日 |
| 精確性 | 精確 | 不精確(月份天數不同) |
| 適用 | 時間間隔 | 日期間隔 |
| 物件 | Instant, LocalTime, LocalDateTime | LocalDate, LocalDateTime |
使用時機
// Duration:精確時間
Duration workHours = Duration.ofHours(8);
Duration timeout = Duration.ofSeconds(30);
Duration latency = Duration.between(requestTime, responseTime);
// Period:日期概念
Period age = Period.between(birthday, today);
Period subscription = Period.ofMonths(3);
Period warranty = Period.ofYears(2);
實際範例
格式化時間差
public String formatDuration(Duration d) {
if (d.isNegative()) {
d = d.negated();
}
long days = d.toDays();
int hours = d.toHoursPart();
int minutes = d.toMinutesPart();
int seconds = d.toSecondsPart();
StringBuilder sb = new StringBuilder();
if (days > 0) sb.append(days).append(" 天 ");
if (hours > 0) sb.append(hours).append(" 小時 ");
if (minutes > 0) sb.append(minutes).append(" 分鐘 ");
if (seconds > 0) sb.append(seconds).append(" 秒");
return sb.toString().trim();
}
// 使用
Duration d = Duration.ofHours(26).plusMinutes(30);
System.out.println(formatDuration(d)); // "1 天 2 小時 30 分鐘"
格式化年齡
public String formatAge(LocalDate birthday) {
Period age = Period.between(birthday, LocalDate.now());
return age.getYears() + " 歲 " + age.getMonths() + " 個月";
}
// 使用
LocalDate birthday = LocalDate.of(1990, 5, 15);
System.out.println(formatAge(birthday)); // "34 歲 7 個月"
倒數計時
public String countdown(LocalDateTime targetTime) {
Duration remaining = Duration.between(LocalDateTime.now(), targetTime);
if (remaining.isNegative()) {
return "已過期";
}
long days = remaining.toDays();
int hours = remaining.toHoursPart();
int minutes = remaining.toMinutesPart();
int seconds = remaining.toSecondsPart();
return String.format("%d 天 %d 小時 %d 分 %d 秒",
days, hours, minutes, seconds);
}
工作時數計算
public Duration calculateWorkHours(List<WorkRecord> records) {
return records.stream()
.map(r -> Duration.between(r.getStartTime(), r.getEndTime()))
.reduce(Duration.ZERO, Duration::plus);
}
重點整理
| 類別 | 用途 | 建立方式 | 運算 |
|---|---|---|---|
| Duration | 時間間隔 | ofHours, ofMinutes, between | plus, minus, multipliedBy |
| Period | 日期間隔 | ofYears, ofMonths, between | plus, minus, multipliedBy |
Duration用於精確的時間計算(秒、毫秒)Period用於日曆概念的日期計算(年、月、日)- 使用
between()計算兩個時間/日期的差距 - 兩者都是不可變物件,運算會回傳新物件