Duration — một lớp bất biến từ gói java.time biểu diễn thời lượng giữa hai thời điểm tính bằng giây và nano giây. Duration đo lường các đại lượng thời gian dựa trên thời gian — giờ, phút, giây, mili giây và nano giây. Theo thông số kỹ thuật từ Oracle Java 17 (2024), khác với Period (đo năm-tháng-ngày), Duration làm việc với các đơn vị thời gian chính xác và không phụ thuộc vào lịch.
Điểm chính
Duration là một lớp mô hình hóa lượng thời gian bằng giây và nano giây. Nó biểu diễn một khoảng thời gian dựa trên thời gian, tức là một số giây vật lý không gắn với lịch. Duration có thể được xem như “125 phút” hoặc “2 giờ 5 phút” — khác với Period sẽ nói “2 tháng”.
Biểu diễn nội bộ của Duration gồm hai trường: long seconds (giây) và int nanos (nano giây, từ 0 đến 999999999). Giá trị có thể âm — điều này có nghĩa là khoảng thời gian “lùi” về quá khứ. Giá trị tối đa là ±31557014167219200 giây.
Theo Baeldung (2024), Duration là lớp chính để tính thời lượng hoạt động, đặt thời gian chờ và đo hiệu suất. Duration bất biến và an toàn luồng, cho phép sử dụng trong môi trường đa luồng mà không cần đồng bộ.
Lớp này triển khai các giao diện Comparable, TemporalAmount và TemporalUnit. TemporalAmount cho phép sử dụng Duration trong các phương thức plus/minus của các lớp LocalTime, LocalDateTime, Instant và ZonedDateTime.
Sự khác biệt chính là Duration đo số giây chính xác (dựa trên thời gian), trong khi Period đo các đơn vị lịch (dựa trên ngày): năm, tháng, ngày. Duration nói: “86400 giây đã trôi qua.” Period nói: “1 ngày đã trôi qua.” Sự khác biệt trở nên rõ ràng trong quá trình chuyển đổi giờ mùa hè — 1 ngày trong Period luôn là 1 ngày lịch, trong khi 86400 giây trong Duration có thể tương ứng với 23 hoặc 25 giờ trong DST.
Duration được sử dụng để đo thời gian vật lý: thời gian chờ kết nối, thời gian thực thi truy vấn, khoảng cách giữa hai Instant. Period được sử dụng cho các tính toán lịch: tuổi của một người (Period.between(dateOfBirth, today)), thời hạn hợp đồng.
Duration làm việc với giây và nano giây, do đó có thể chia thành các phần (giờ, phút). Period làm việc với năm, tháng và ngày — các đơn vị lịch không thể chia. Theo Oracle Java Tutorial (2024), việc lựa chọn giữa Duration và Period phụ thuộc vào loại tác vụ: thời gian chính xác so với ngày lịch.
Cách phổ biến nhất là Duration.between(Temporal start, Temporal end). Temporal có thể là Instant, LocalTime, LocalDateTime, ZonedDateTime — bất kỳ loại nào triển khai Temporal. Phương thức trả về Duration biểu diễn chênh lệch start - end (có thể âm).
Các phương thức factory tĩnh: Duration.ofSeconds(long), ofMinutes(long), ofHours(long), ofDays(long), ofMillis(long), ofNanos(long). Cũng có of(long amount, TemporalUnit unit) cho các đơn vị tùy ý — ChronoUnit.HOURS, ChronoUnit.MINUTES và các đơn vị khác.
Phương thức parse(CharSequence) chấp nhận chuỗi ở định dạng ISO-8601: “PT1H30M” (1 giờ 30 phút), “PT45S” (45 giây), “P2DT3H” (2 ngày 3 giờ). Chuỗi luôn bắt đầu bằng “PT” (Period of Time).
val betweenMoments = Duration.between(
Instant.parse("2026-07-21T10:00:00Z"),
Instant.parse("2026-07-21T14:30:00Z")
)
val fromMinutes = Duration.ofMinutes(90)
val fromHours = Duration.ofHours(2)
val parsed = Duration.parse("PT1H30M")
Duration hỗ trợ một tập hợp đầy đủ các phép toán số học. Các phương thức plus(Duration) và minus(Duration) thêm hoặc bớt một khoảng thời gian khác. Các phương thức plusDays(), plusHours(), plusMinutes(), plusSeconds(), plusMillis(), plusNanos() — để thêm các đơn vị cụ thể.
Để nhân và chia, sử dụng multipliedBy(long) và dividedBy(long). Duration.multipliedBy(2) nhân đôi khoảng thời gian. Duration.dividedBy(3) chia thành ba phần với làm tròn xuống. Phương thức negated() đảo ngược dấu — dương thành âm và ngược lại.
Phương thức abs() trả về Duration với giá trị tuyệt đối (dương). isNegative() và isZero() là các kiểm tra. toDays(), toHours(), toMinutes(), toSeconds(), toMillis(), toNanos() chuyển đổi sang các đơn vị tương ứng.
val oneHour = Duration.ofHours(1)
val twoHours = oneHour.plus(Duration.ofMinutes(60))
val halfHour = oneHour.dividedBy(2)
val minutes = twoHours.toMinutes()
val absDuration = (Duration.ofHours(-1)).abs()
Duration triển khai giao diện Comparable, cho phép so sánh các khoảng thời gian một cách tự nhiên. Phương thức compareTo() trả về số âm, không hoặc dương. isNegative() và isZero() là các kiểm tra nhanh. Để so sánh tường minh, sử dụng equals() — hai Duration bằng nhau nếu giây và nano giây của chúng khớp nhau.
Vì Duration có thể âm, các so sánh “lớn hơn” hoặc “nhỏ hơn” hoạt động có xét đến dấu. -5 phút nhỏ hơn 2 phút. Phương thức abs() hữu ích để so sánh độ dài “tuyệt đối” bất kể hướng nào.
Trong Kotlin, Duration hỗ trợ các toán tử so sánh thông qua nạp chồng toán tử: a < b, a > b, a <= b. Ngoài ra, plus và minus cũng có sẵn dưới dạng toán tử: a + b, a - b.
val short = Duration.ofMinutes(5)
val long = Duration.ofMinutes(10)
if (short < long) {
Log.d("Duration", "5 phút ít hơn 10")
}
val negative = Duration.ofMinutes(-3)
Log.d("Duration", "Âm: ${negative.isNegative()}")
Ví dụ đầu tiên là cấu hình đồng bộ định kỳ với máy chủ. Duration được sử dụng để tính khoảng cách giữa các lần đồng bộ và kiểm tra xem giới hạn thời gian không có cập nhật có bị vượt quá hay không.
data class SyncConfig(
val interval: Duration = Duration.ofMinutes(15),
val retryDelay: Duration = Duration.ofSeconds(30)
)
fun calculateNextSync(
lastSync: Instant,
config: SyncConfig
): Duration {
val elapsed = Duration.between(lastSync, Instant.now())
return config.interval.minus(elapsed)
.coerceAtLeast(Duration.ZERO)
}
Ví dụ thứ hai là đo thời gian thực thi hoạt động để ghi log hiệu suất.
fun measureExecution(
tag: String,
block: () -> Unit
) {
val start = Instant.now()
block()
val duration = Duration.between(start, Instant.now())
Log.d(tag, "Đã thực thi trong ${duration.toMillis()} ms")
}
Ví dụ thứ ba là tính thời gian còn lại của bộ đếm thời gian (ví dụ: đếm ngược đến khi kết thúc chương trình khuyến mãi).
class CountdownTimer(
private val expiresAt: Instant
) {
fun getRemainingTime(): Duration {
val remaining = Duration.between(
Instant.now(), expiresAt
)
return remaining.coerceAtLeast(Duration.ZERO)
}
fun isExpired(): Boolean = getRemainingTime() == Duration.ZERO
}
Phương thức toString() trả về Duration ở định dạng ISO-8601: “PT1H30M” (1 giờ 30 phút), “PT45.5S” (45.5 giây). Định dạng này thuận tiện cho trao đổi máy móc nhưng không phù hợp để hiển thị cho người dùng.
Để có định dạng con người có thể đọc được, hãy sử dụng toDays(), toHours(), toMinutes(), toSeconds() sau đó tự xây dựng chuỗi. Ví dụ: “${days} ng ${hours} giờ ${minutes} phút”. Lưu ý rằng toHours() trả về tổng số giờ, không phải số giờ trong ngày.
Để phân tích Duration thành các thành phần, sử dụng công thức: val hours = duration.toHours(); val minutes = duration.toMinutes() % 60; val seconds = duration.seconds % 60. Theo Apache Commons Lang (2024), thư viện DurationFormatUtils cung cấp các khả năng định dạng bổ sung.
fun formatDuration(duration: Duration): String {
val hours = duration.toHours()
val minutes = duration.toMinutes() % 60
val seconds = duration.seconds % 60
return buildString {
if (hours > 0) append("${hours} h ")
if (minutes > 0) append("${minutes} min ")
append("${seconds} sec")
}
}
Lỗi đầu tiên là nhầm lẫn giữa Duration và Period khi làm việc với ngày. Duration đo giây, do đó Duration.ofDays(1) luôn là 24 giờ (86400 giây), bất kể chuyển đổi giờ mùa hè. Nếu cần một ngày lịch, hãy sử dụng Period.ofDays(1).
Lỗi thứ hai là mất nano giây trong quá trình chuyển đổi. Duration có thể lưu trữ nano giây, nhưng toMillis() và toSeconds() loại bỏ chúng. Để tính toán chính xác, hãy sử dụng toNanos() hoặc làm việc trực tiếp với Duration mà không chuyển đổi thành kiểu nguyên thủy.
Lỗi thứ ba là bỏ qua Duration âm. Duration.between(start, end) trả về start - end. Nếu start sau end, Duration sẽ âm. Phương thức abs() giúp lấy giá trị tuyệt đối và isNegative() kiểm tra thứ tự đối số.
Lỗi thứ tư là định dạng Duration không đúng cho giao diện người dùng. Duration.toString() trả về ISO-8601 không thể đọc được. Luôn định dạng Duration thủ công để hiển thị cho người dùng bằng toHours(), toMinutes() và toSeconds() với phần dư chính xác của phép chia.
Câu hỏi thường gặp
Có, Duration có thể âm. Duration.between(start, end) trả về start - end. Nếu start sau end, Duration sẽ âm. Sử dụng abs() để lấy giá trị tuyệt đối hoặc isNegative() để kiểm tra.
Sử dụng phương thức plus(Duration) hoặc toán tử + trong Kotlin: duration1 + duration2. Kết quả là một Duration mới. Phương thức minus(Duration) trừ một khoảng thời gian khỏi khoảng thời gian khác. Tất cả các thao tác đều bất biến và trả về một đối tượng mới.
Duration.ofDays(1) luôn là 24 giờ (86400 giây). Period.ofDays(1) là 1 ngày lịch, có thể là 23 hoặc 25 giờ trong DST. Để tính toán thời gian chính xác, hãy sử dụng Duration; để tính toán lịch, hãy sử dụng Period.
Sử dụng phương thức toMillis(). Nó trả về long — số mili giây trong Duration. Đối với nano giây, sử dụng toNanos(). Lưu ý: toNanos() có thể tràn long ở các giá trị > 292 năm. Đối với Duration lớn, hãy sử dụng toSeconds() hoặc toMinutes().
Sử dụng Duration.between(startTime, endTime). Nếu endTime nhỏ hơn startTime (ca đêm), Duration sẽ âm. Thêm 24 giờ: duration.plusHours(24), nếu endTime được coi là ngày hôm sau.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm