Java Duration
Duration 是 Java 8 引入的類別,用於表示兩個時間點之間的時間間隔,以秒和奈秒為單位。適合處理基於時間的間隔(時、分、秒)。
引入套件
import java.time.Duration;
建立 Duration
使用 of 方法
// 指定天數
Duration days = Duration.ofDays(5); // PT120H (5天 = 120小時)
// 指定小時
Duration hours = Duration.ofHours(8); // PT8H
// 指定分鐘
Duration minutes = Duration.ofMinutes(30); // PT30M
// 指定秒數
Duration seconds = Duration.ofSeconds(90); // PT1M30S
// 指定毫秒
Duration millis = Duration.ofMillis(500); // PT0.5S
// 指定奈秒
Duration nanos = Duration.ofNanos(1000000); // PT0.001S
使用 of 方法搭配 ChronoUnit
Duration d1 = Duration.of(5, ChronoUnit.HOURS); // PT5H
Duration d2 = Duration.of(30, ChronoUnit.MINUTES); // PT30M
Duration d3 = Duration.of(1, ChronoUnit.DAYS); // PT24H
從字串解析
// ISO-8601 格式:PT[n]H[n]M[n]S
Duration d1 = Duration.parse("PT2H30M"); // 2小時30分
Duration d2 = Duration.parse("PT1H30M45S"); // 1小時30分45秒
Duration d3 = Duration.parse("PT0.5S"); // 0.5秒
Duration d4 = Duration.parse("P2DT3H"); // 2天3小時
計算兩個時間的間隔
LocalTime start = LocalTime.of(9, 0);
LocalTime end = LocalTime.of(17, 30);
Duration duration = Duration.between(start, end);
System.out.println(duration); // PT8H30M
// 也可用於 LocalDateTime、Instant 等
Instant t1 = Instant.now();
// ... 執行操作 ...
Instant t2 = Instant.now();
Duration elapsed = Duration.between(t1, t2);
取得 Duration 資訊
Duration duration = Duration.ofHours(2).plusMinutes(30).plusSeconds(45);
// 取得總量
long totalSeconds = duration.getSeconds(); // 9045
int nanos = duration.getNano(); // 0
// 取得各單位的值(Java 9+)
long days = duration.toDays(); // 0
long hours = duration.toHours(); // 2
long minutes = duration.toMinutes(); // 150
long seconds = duration.toSeconds(); // 9045
long millis = duration.toMillis(); // 9045000
long nanoTotal = duration.toNanos(); // 9045000000000
// 取得各部分的值(Java 9+)
int hoursPart = duration.toHoursPart(); // 2
int minutesPart = duration.toMinutesPart(); // 30
int secondsPart = duration.toSecondsPart(); // 45
int millisPart = duration.toMillisPart(); // 0
int nanosPart = duration.toNanosPart(); // 0
Duration 運算
加減運算
Duration d1 = Duration.ofHours(2);
Duration d2 = Duration.ofMinutes(30);
// 加法
Duration sum = d1.plus(d2); // PT2H30M
Duration plusHours = d1.plusHours(1); // PT3H
Duration plusMins = d1.plusMinutes(15); // PT2H15M
// 減法
Duration diff = d1.minus(d2); // PT1H30M
Duration minusHours = d1.minusHours(1); // PT1H
乘除運算
Duration d = Duration.ofMinutes(30);
Duration doubled = d.multipliedBy(2); // PT1H
Duration halved = d.dividedBy(2); // PT15M
// 兩個 Duration 相除(Java 9+)
Duration d1 = Duration.ofHours(2);
Duration d2 = Duration.ofMinutes(30);
long ratio = d1.dividedBy(d2); // 4
取絕對值和取反
Duration negative = Duration.ofHours(-2);
Duration absolute = negative.abs(); // PT2H
Duration negated = negative.negated(); // PT2H
Duration positive = Duration.ofHours(2);
Duration neg = positive.negated(); // PT-2H
Duration 比較
Duration d1 = Duration.ofHours(2);
Duration d2 = Duration.ofMinutes(90);
int result = d1.compareTo(d2); // 正數(d1 較長)
boolean isZero = d1.isZero(); // false
boolean isNegative = d1.isNegative(); // false
boolean isPositive = !d1.isNegative() && !d1.isZero(); // true
// 快速比較(Java 18+)
// boolean isPositive = d1.isPositive();
應用於時間運算
LocalDateTime now = LocalDateTime.now();
Duration duration = Duration.ofHours(2).plusMinutes(30);
// 加上 Duration
LocalDateTime later = now.plus(duration);
// 減去 Duration
LocalDateTime earlier = now.minus(duration);
// 用於 Instant
Instant instant = Instant.now();
Instant futureInstant = instant.plus(Duration.ofDays(1));
實用範例
格式化顯示
public static String formatDuration(Duration duration) {
long hours = duration.toHours();
int minutes = duration.toMinutesPart();
int seconds = duration.toSecondsPart();
if (hours > 0) {
return String.format("%d 小時 %d 分 %d 秒", hours, minutes, seconds);
} else if (minutes > 0) {
return String.format("%d 分 %d 秒", minutes, seconds);
} else {
return String.format("%d 秒", seconds);
}
}
Duration d = Duration.ofSeconds(3725);
System.out.println(formatDuration(d)); // 1 小時 2 分 5 秒
執行時間計算
public static <T> T measureTime(Supplier<T> task, String taskName) {
Instant start = Instant.now();
T result = task.get();
Duration elapsed = Duration.between(start, Instant.now());
System.out.printf("%s 耗時: %d ms%n", taskName, elapsed.toMillis());
return result;
}
// 使用
String result = measureTime(() -> {
// 模擬耗時操作
try { Thread.sleep(1500); } catch (Exception e) {}
return "完成";
}, "資料處理");
倒數計時
public static void countdown(Duration duration) throws InterruptedException {
Instant endTime = Instant.now().plus(duration);
while (Instant.now().isBefore(endTime)) {
Duration remaining = Duration.between(Instant.now(), endTime);
System.out.printf("\r剩餘時間: %02d:%02d:%02d",
remaining.toHours(),
remaining.toMinutesPart(),
remaining.toSecondsPart()
);
Thread.sleep(1000);
}
System.out.println("\n時間到!");
}
// 5分鐘倒數
countdown(Duration.ofMinutes(5));
工作時數計算
public static Duration calculateWorkHours(LocalTime clockIn, LocalTime clockOut, Duration breakTime) {
Duration totalTime = Duration.between(clockIn, clockOut);
return totalTime.minus(breakTime);
}
LocalTime in = LocalTime.of(9, 0);
LocalTime out = LocalTime.of(18, 0);
Duration lunch = Duration.ofHours(1);
Duration workHours = calculateWorkHours(in, out, lunch);
System.out.println("工作時數: " + workHours.toHours() + " 小時"); // 8 小時
速率限制
public class RateLimiter {
private final Duration interval;
private Instant lastAction;
public RateLimiter(Duration interval) {
this.interval = interval;
this.lastAction = Instant.EPOCH;
}
public boolean tryAcquire() {
Instant now = Instant.now();
if (Duration.between(lastAction, now).compareTo(interval) >= 0) {
lastAction = now;
return true;
}
return false;
}
public Duration getWaitTime() {
Duration elapsed = Duration.between(lastAction, Instant.now());
Duration wait = interval.minus(elapsed);
return wait.isNegative() ? Duration.ZERO : wait;
}
}
// 每秒最多執行一次
RateLimiter limiter = new RateLimiter(Duration.ofSeconds(1));
if (limiter.tryAcquire()) {
System.out.println("執行操作");
} else {
System.out.println("請等待 " + limiter.getWaitTime().toMillis() + " ms");
}
Duration vs Period
| 特性 | Duration | Period |
|---|---|---|
| 單位 | 秒、奈秒 | 年、月、日 |
| 精度 | 奈秒級 | 天級 |
| 用途 | 時間間隔(時分秒) | 日期間隔(年月日) |
| 適用類型 | LocalTime, Instant | LocalDate |
// Duration:時間間隔
Duration duration = Duration.ofHours(5);
LocalTime time = LocalTime.of(10, 0);
LocalTime newTime = time.plus(duration); // 15:00
// Period:日期間隔
Period period = Period.ofMonths(2);
LocalDate date = LocalDate.of(2024, 1, 15);
LocalDate newDate = date.plus(period); // 2024-03-15
重點整理
Duration表示基於時間的間隔(秒和奈秒)- 使用
ofXxx()方法建立各種時間長度 - 使用
between()計算兩個時間點的間隔 - 支援加減乘除運算
- 是不可變(immutable)類別
- 適合用於
LocalTime、Instant、LocalDateTime - 日期間隔(年月日)應使用
Period