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 є незмінним та потокобезпечним, що дозволяє використовувати його в багатопотоковому середовищі без синхронізації.

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

Duration vs Period: в чому різниця?

Головна відмінність полягає в тому, що Duration вимірює точну кількість секунд (на основі часу), тоді як Period вимірює календарні одиниці (на основі дати): роки, місяці, дні. Duration каже: «пройшло 86400 секунд». Period каже: «пройшов 1 день». Різниця проявляється під час переведення на літній час — 1 день в Period завжди є 1 календарний день, а 86400 секунд в Duration можуть відповідати 23 або 25 годинам під час DST.

Duration використовується для вимірювання фізичного часу: таймаути підключення, час виконання запиту, інтервали між двома Instant. Period використовується для календарних розрахунків: вік людини (Period.between(dateOfBirth, today)), термін дії контракту.

Duration працює з секундами та наносекундами, тому його можна ділити на частини (години, хвилини). Period працює з роками, місяцями та днями — неподільні календарні одиниці. Згідно з Oracle Java Tutorial (2024), вибір між Duration та Period залежить від типу завдання: точний час проти календарних дат.

Створення 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()} мс")
}

Третій приклад — розрахунок часу залишку таймера (наприклад, зворотний відлік до закінчення акції).

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 для інтерфейсу користувача. 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 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також