Duration — nó là gì, tính toán thời lượng trong Android

Tác giả: IT Sectr Đã đăng: 2026-07-13 Thời gian đọc: 9 phút

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ớp bất biến để đo thời lượng bằng giây và nano giây.
  • Khác với Period, Duration làm việc với đơn vị dựa trên thời gian (giờ, phút, giây), không phải dựa trên ngày (ngày, tháng, năm).
  • Được tạo qua Duration.between(start, end), Duration.ofMinutes(), Duration.ofHours() và các phương thức factory tĩnh khác.
  • Hỗ trợ các phép toán số học: plus(), minus(), multipliedBy(), dividedBy(), negated().
  • Đối với phát triển Android, Duration thuận tiện để tính toán thời gian chờ, khoảng đồng bộ và thời lượng hoạt động.

Duration là gì?

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, TemporalAmountTemporalUnit. 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.

Duration vs Period: khác biệt là gì?

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.

Tạo Duration

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).

kotlin
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")

Số học với Duration

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)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.

kotlin
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()

So sánh Duration

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.

kotlin
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()}")

Duration trong các tác vụ Android thực tế

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.

kotlin
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.

kotlin
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).

kotlin
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
}

Chuyển đổi Duration thành chuỗi

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.

kotlin
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 thường gặp

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

Duration có thể âm không?

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.

Làm thế nào để cộng hai Duration?

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) khác Period.ofDays(1) như thế nào?

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.

Làm thế nào để chuyển đổi Duration thành mili giây?

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().

Làm thế nào để tính Duration giữa hai LocalTime?

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

  • Duration — lớp bất biến cho khoảng thời gian dựa trên thời gian với độ chính xác nano giây, lý tưởng để đo khoảng cách.
  • Sự khác biệt chính với Period — Duration đo giây (thời gian vật lý), Period đo các đơn vị lịch.
  • Được tạo qua Duration.between() cho chênh lệch giữa các thời điểm hoặc qua các factory tĩnh ofMinutes, ofHours, ofDays.
  • Hỗ trợ số học: plus, minus, multipliedBy, dividedBy, cũng như so sánh qua Comparable và abs.
  • Trong Android, Duration được sử dụng để tính thời gian chờ, khoảng đồng bộ, bộ đếm thời gian và đo hiệu suất.
  • Khi hiển thị cho người dùng, hãy định dạng Duration thủ công — toString() xuất ra ISO-8601 không thể đọc được.
  • Hãy nhớ rằng Duration có thể âm — kiểm tra isNegative() và sử dụng abs() để tính toán chính xác.

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.

Thảo luận dự án

Đọc thêm