Duration — какво е, изчисляване на продължителност в Android

Автор: IT Sectr Публикувано: 2026-07-13 Време за четене: 9 мин

Duration — непроменяем клас от пакета java.time, представяващ продължителност между два момента от време в секунди и наносекунди. Duration измерва базирано на времето количество време — часове, минути, секунди, милисекунди и наносекунди. Според спецификацията на Oracle Java 17 (2024), за разлика от Period (който измерва години-месеци-дни), Duration работи с точни единици за време и не зависи от календара.

Основни поенти

  • Duration — непроменяем клас за измерване на продължителност в секунди и наносекунди.
  • За разлика от Period, Duration работи с базирани на времето единици (часове, минути, секунди), а не базирани на дата (дни, месеци, години).
  • Създава се чрез Duration.between(start, end), Duration.ofMinutes(), Duration.ofHours() и други статични фабрики.
  • Подкрепя аритметични операции: plus(), minus(), multipliedBy(), dividedBy(), negated().
  • За Android разработка, Duration е удобен за изчисляване на таймаути, интервали за синхронизация и продължителност на операции.

Какво е Duration?

Duration — е клас, който моделира количеството време в секунди и наносекунди. Той представлява базирана на времето продължителност, тоест физическия брой секунди, невързан към календар. Duration може да бъде представен като „125 минути” или „2 часа 5 минути” — за разлика от Period, който ще каже „2 месеца”.

Вътрешното представяне на Duration се състои от два полета: long seconds (секунди) и int nanos (наносекунди, от 0 до 999999999). Стойността може да бъде отрицателна — това означава продължителност „назад” във времето. Максималната стойност е ±31557014167219200 секунди.

Според Baeldung (2024), Duration е ключов клас за изчисляване на продължителност на операции, настройване на таймаути и измерване на производителност. Duration е непроменяем и thread-safe, което позволява използването му в многонишкова среда без синхронизация.

Класът имплементира интерфейсите Comparable, TemporalAmount и TemporalUnit. TemporalAmount позволява използване на Duration в методите plus/minus на класовете LocalTime, LocalDateTime, Instant и ZonedDateTime.

Duration vs Period: каква е разликата?

Основната разлика — Duration измерва точния брой секунди (time-based), докато Period измерва календарни единици (date-based): години, месеци, дни. Duration казва: „изминаха 86400 секунди”. Period казва: „измина 1 ден”. Разликата се проявява при прехода към лятно часово време — 1 ден в Period е винаги равен на 1 ден в календара, а 86400 секунди в Duration могат да съответстват на 23 или 25 часа при DST.

Duration се използва за измерване на физическо време: таймаути за връзка, време за изпълнение на заявка, интервал между два Instant. Period се използва за календарни изчисления: възраст на човек (Period.between(датаНаРаждане, днес)), срок на валидност на договор.

Duration работи с секунди и наносекунди, така че може да бъде разделен на части (часове, минути). Period работи с години, месеци и дни — неделими календарни единици. Според Oracle Java Tutorial (2024), изборът между Duration и Period зависи от типа задача: точно време vs календарни дати.

Създаване на Duration

Най-разпространеният начин — Duration.between(Temporal start, Temporal end). Temporal може да бъде Instant, LocalTime, LocalDateTime, ZonedDateTime — всякакъв тип, който имплементира Temporal. Методът връща Duration, представляваща разликата start - end (може да бъде отрицателна).

Статични фабрични методи: Duration.ofSeconds(long), ofMinutes(long), ofHours(long), ofDays(long), ofMillis(long), ofNanos(long). Съществува и of(long amount, TemporalUnit unit) за произволни единици — ChronoUnit.HOURS, ChronoUnit.MINUTES и други.

Методът parse(CharSequence) приема низ в ISO-8601 формат: „PT1H30M” (1 час 30 минути), „PT45S” (45 секунди), „P2DT3H” (2 дни 3 часа). Низът винаги започва с „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")

Аритметика с Duration

Duration подкрепя пълен набор от аритметични операции. Методите plus(Duration) и minus(Duration) добавят или изваждат друга продължителност. Методите plusDays(), plusHours(), plusMinutes(), plusSeconds(), plusMillis(), plusNanos() — за точно добавяне на единици.

За умножение и делене се използват multipliedBy(long) и dividedBy(long). Duration.multipliedBy(2) удвоява продължителността. Duration.dividedBy(3) разделя на три части с закръгляне надолу. Методът negated() обърща знака — положителният става отрицателен и обратно.

Методът abs() връща Duration с абсолютна (положителна) стойност. isNegative() и isZero() — проверки. toDays(), toHours(), toMinutes(), toSeconds(), toMillis(), toNanos() — преобразуване в съответните единици.

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

Сравняване на Duration

Duration имплементира интерфейса Comparable, което позволява естествено сравняване на продължителности. Методът compareTo() връща отрицателно число, нула или положително число. Методите isNegative() и isZero() — бързи проверки. За явно сравнение използвайте equals() — два Duration са равни, ако имат еднакви секунди и наносекунди.

Тъй като Duration може да бъде отрицателно, сравнението „по-голямо” или „по-малко” работи, като взема предвид знака. -5 минути е по-малко от 2 минути. Методът abs() е полезен, ако трябва да сравнявате „абсолютни” дължини независимо от посоката.

В Kotlin, Duration подкрепя операторите за сравнение чрез предефиниране на оператори: a < b, a > b, a <= b. Също така plus и minus са налични като оператори: a + b, a - b.

kotlin
val short = Duration.ofMinutes(5)
val long = Duration.ofMinutes(10)

if (short < long) {
    Log.d("Duration", "5 мин е по-малко от 10")
}

val negative = Duration.ofMinutes(-3)
Log.d("Duration", "Отрицателен: ${negative.isNegative()}")

Duration в реални Android задачи

Първият пример — настройка на периодична синхронизация с сървъра. Duration се използва за изчисляване на интервала между синхронизации и проверка дали лимитът на времето без обновяване е надвършен.

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

Вторият пример — измерване на времето за изпълнение на операция за логване на производителността.

kotlin
fun measureExecution(
    tag: String,
    block: () -> Unit
) {
    val start = Instant.now()
    block()
    val duration = Duration.between(start, Instant.now())
    Log.d(tag, "Изпълнено за ${duration.toMillis()} ms")
}

Третият пример — изчисляване на оставащото време на таймер (например, за отброяване до края на промоция).

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
}

Преобразуване на Duration в низ

Методът toString() връща Duration в ISO-8601 формат: „PT1H30M” (1 час 30 минути), „PT45.5S” (45.5 секунди). Този формат е удобен за машинен обмен, но не за показване на потребителя.

За човешки четив формат използвайте toDays(), toHours(), toMinutes(), toSeconds() с ръчно съставяне на низа. Например: „${days} д ${hours} ч ${minutes} мин”. Имайте предвид, че toHours() връща общия брой часове, а не часовете в рамките на един ден.

За разделяне на Duration на компоненти се използва формулата: val hours = duration.toHours(); val minutes = duration.toMinutes() % 60; val seconds = duration.seconds % 60. Според Apache Commons Lang (2024), библиотеката DurationFormatUtils предоставя допълнителни възможности за форматиране.

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

Типични грешки

Първа грешка — объркване на Duration и Period при работа с дати. Duration измерва секунди, така че Duration.ofDays(1) е винаги 24 часа (86400 секунди), независимо от прехода към лятно часово време. Ако имате нужда от календарен ден, използвайте Period.ofDays(1).

Втора грешка — загуба на наносекунди при преобразуване. Duration може да съхранява наносекунди, но toMillis() и toSeconds() ги изхвърлят. За точни изчисления използвайте toNanos() или работете директно с Duration, без преобразуване в примитивни типове.

Трета грешка — игнориране на отрицателни Duration. Duration.between(start, end) връща start - end. Ако start е след end, Duration ще бъде отрицателно. Методът abs() помага да получите абсолютната стойност, а isNegative() — да проверите реда на аргументите.

Четвърта грешка — неправилно форматиране на Duration за UI. Duration.toString() връща ISO-8601, който е нечетив. Винаги форматирайте Duration ръчно за показване на потребителя, използвайки toHours(), toMinutes() и toSeconds() с правилния остатък от деленето.

Често задавани въпроси

Може ли Duration да бъде отрицателно?

Да, Duration може да бъде отрицателно. Duration.between(start, end) връща start - end. Ако start е след end, Duration ще бъде отрицателно. Използвайте abs() за получаване на абсолютната стойност или isNegative() за проверка.

Как да събера две Duration?

Използвайте метода plus(Duration) или оператора + в Kotlin: duration1 + duration2. Резултатът — ново Duration. Методът minus(Duration) изважда една продължителност от друга. Всички операции са непроменяеми и връщат нов обект.

По какво се различава Duration.ofDays(1) от Period.ofDays(1)?

Duration.ofDays(1) е винаги 24 часа (86400 секунди). Period.ofDays(1) е 1 календарен ден, който при DST може да бъде 23 или 25 часа. За изчисления с точно време използвайте Duration, за календарни — Period.

Как да преобразувам Duration в милисекунди?

Използвайте метода toMillis(). Той връща long — броя милисекунди в Duration. За наносекунди използвайте toNanos(). Внимание: toNanos() може да препълни long при стойности > 292 години. За големи Duration използвайте toSeconds() или toMinutes().

Как да изчисля Duration между два LocalTime?

Използвайте Duration.between(startTime, endTime). Ако endTime е по-малко от startTime (нощна смяна), Duration ще бъде отрицателно. Добавете 24 часа: duration.plusHours(24), ако предполагате, че endTime е следващият ден.

Резюме

  • Duration — непроменяем клас за базирана на времето продължителност с точност до наносекунда, идеален за измерване на интервали.
  • Основната разлика от Period — Duration измерва секунди (физическо време), Period — календарни единици.
  • Създава се чрез Duration.between() за разлика между моменти или чрез статични фабрики ofMinutes, ofHours, ofDays.
  • Подкрепя аритметика: plus, minus, multipliedBy, dividedBy, както и сравнение чрез Comparable и abs.
  • В Android, Duration се прилага за изчисляване на таймаути, интервали за синхронизация, таймери и измерване на производителност.
  • При показване на потребителя форматирайте Duration ръчно — toString() връща ISO-8601, нечетив за човек.
  • Имайте предвид, че Duration може да бъде отрицателно — проверявайте isNegative() и използвайте abs() за коректни изчисления.

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също