Duration — co to jest, obliczanie czasu trwania w Androidzie

Autor: IT Sectr Opublikowano: 2026-07-13 Czas czytania: 9 min

Duration — niemutowalna klasa z pakietu java.time, reprezentująca czas trwania pomiędzy dwoma momentami w sekundach i nanosekundach. Duration mierzy ilość czasu opartą na czasie — godziny, minuty, sekundy, milisekundy i nanosekundy. Według specyfikacji Oracle Java 17 (2024), w przeciwieństwie do Period (który mierzy lata-miesiące-dni), Duration działa z dokładnymi jednostkami czasu i nie zależy od kalendarza.

Najważniejsze

  • Duration — niemutowalna klasa do pomiaru czasu trwania w sekundach i nanosekundach.
  • W przeciwieństwie do Period, Duration działa z jednostkami opartymi na czasie (godziny, minuty, sekundy), a nie na dacie (dni, miesiące, lata).
  • Tworzona przez Duration.between(start, end), Duration.ofMinutes(), Duration.ofHours() i inne statyczne fabryki.
  • Obsługuje operacje arytmetyczne: plus(), minus(), multipliedBy(), dividedBy(), negated().
  • W Androidzie Duration jest wygodny do obliczania timeoutów, interwałów synchronizacji i czasu trwania operacji.

Czym jest Duration?

Duration — to klasa modelująca ilość czasu w sekundach i nanosekundach. Reprezentuje czas trwania oparty na czasie, czyli fizyczną liczbę sekund, niezwiązaną z kalendarzem. Duration można przedstawić jako „125 minut” lub „2 godziny 5 minut” — w przeciwieństwie do Period, który powie „2 miesiące”.

Wewnętrzna reprezentacja Duration składa się z dwóch pól: long seconds (sekund) i int nanos (nanosekund, od 0 do 999999999). Wartość może być ujemna — oznacza to czas trwania „wstecz” w czasie. Maksymalna wartość to ±31557014167219200 sekund.

Według Baeldung (2024), Duration to kluczowa klasa do obliczania czasu trwania operacji, ustawiania timeoutów i pomiaru wydajności. Duration jest niemutowalna i bezpieczna wątkowo, co pozwala na jej używanie w środowisku wielowątkowym bez synchronizacji.

Klasa implementuje interfejsy Comparable, TemporalAmount i TemporalUnit. TemporalAmount umożliwia używanie Duration w metodach plus/minus klas LocalTime, LocalDateTime, Instant i ZonedDateTime.

Duration vs Period: jaka jest różnica?

Główna różnica — Duration mierzy dokładną liczbę sekund (time-based), a Period mierzy jednostki kalendarzowe (date-based): lata, miesiące, dni. Duration mówi: „minęło 86400 sekund”. Period mówi: „minął 1 dzień”. Różnica ujawnia się przy zmianie czasu na letni — 1 dzień w Period zawsze równa się 1 dniowi w kalendarzu, a 86400 sekund w Duration może odpowiadać 23 lub 25 godzinom przy DST.

Duration jest używane do pomiaru fizycznego czasu: timeouty połączenia, czas wykonania zapytania, interwał pomiędzy dwoma Instant. Period jest używane do obliczeń kalendarzowych: wiek osoby (Period.between(dataUrodzenia, dzisiaj)), okres ważności umowy.

Duration działa z sekundami i nanosekundami, więc można je dzielić na części (godziny, minuty). Period działa z latami, miesiącami i dniami — niepodzielnymi jednostkami kalendarzowymi. Według Oracle Java Tutorial (2024), wybór między Duration a Period zależy od rodzaju zadania: dokładny czas vs daty kalendarzowe.

Tworzenie Duration

Najczęstszy sposób — Duration.between(Temporal start, Temporal end). Temporal może być Instant, LocalTime, LocalDateTime, ZonedDateTime — dowolny typ implementujący Temporal. Metoda zwraca Duration reprezentującą różnicę start - end (może być ujemna).

Statyczne metody fabryczne: Duration.ofSeconds(long), ofMinutes(long), ofHours(long), ofDays(long), ofMillis(long), ofNanos(long). Jest też of(long amount, TemporalUnit unit) dla dowolnych jednostek — ChronoUnit.HOURS, ChronoUnit.MINUTES i innych.

Metoda parse(CharSequence) przyjmuje ciąg w formacie ISO-8601: „PT1H30M” (1 godzina 30 minut), „PT45S” (45 sekund), „P2DT3H” (2 dni 3 godziny). Ciąg zawsze zaczyna się od „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")

Arytmetyka z Duration

Duration obsługuje pełny zestaw operacji arytmetycznych. Metody plus(Duration), minus(Duration) dodają lub odejmują inną długość. Metody plusDays(), plusHours(), plusMinutes(), plusSeconds(), plusMillis(), plusNanos() — do dodawania poszczególnych jednostek.

Do mnożenia i dzielenia służą multipliedBy(long) i dividedBy(long). Duration.multipliedBy(2) podwaja czas trwania. Duration.dividedBy(3) dzieli na trzy części z zaokrągleniem w dół. Metoda negated() odwraca znak — dodatnia staje się ujemna i odwrotnie.

Metoda abs() zwraca Duration z wartością bezwzględną (dodatnią). isNegative() i isZero() — sprawdzenia. Do konwersji między Duration służą toDays(), toHours(), toMinutes(), toSeconds(), toMillis(), toNanos() — konwersja do odpowiednich jednostek.

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

Porównywanie Duration

Duration implementuje interfejs Comparable, co pozwala na naturalne porównywanie czasów trwania. Metoda compareTo() zwraca liczbę ujemną, zero lub dodatnią. Metody isNegative() i isZero() — szybkie sprawdzenia. Do jawnego porównania używaj equals() — dwa Duration są równe, jeśli mają takie same sekundy i nanosekundy.

Ponieważ Duration może być ujemne, porównanie ‚większy” lub „mniejszy” działa z uwzględnieniem znaku. -5 minut jest mniejsze niż 2 minuty. Metoda abs() jest przydatna, jeśli potrzebujesz porównywać „bezwzględne” długości niezależnie od kierunku.

W Kotlinie Duration obsługuje operatory porównania przez przeciążanie operatorów: a < b, a > b, a <= b. Dostępne są również plus i minus jako operatory: a + b, a - b.

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

if (short < long) {
    Log.d("Duration", "5 min to mniej niż 10")
}

val negative = Duration.ofMinutes(-3)
Log.d("Duration", "Ujemny: ${negative.isNegative()}")

Duration w rzeczywistych zadaniach Androida

Pierwszy przykład — konfiguracja okresowej synchronizacji z serwerem. Duration jest używane do obliczania interwału między synchronizacjami i sprawdzania, czy limit czasu bez aktualizacji nie został przekroczony.

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

Drugi przykład — pomiar czasu wykonania operacji do logowania wydajności.

kotlin
fun measureExecution(
    tag: String,
    block: () -> Unit
) {
    val start = Instant.now()
    block()
    val duration = Duration.between(start, Instant.now())
    Log.d(tag, "Wykonano w ${duration.toMillis()} ms")
}

Trzeci przykład — obliczanie pozostałego czasu timera (na przykład do odliczania do zakończenia promocji).

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
}

Konwersja Duration na ciąg znaków

Metoda toString() zwraca Duration w formacie ISO-8601: „PT1H30M” (1 godzina 30 minut), „PT45.5S” (45.5 sekund). Ten format jest wygodny do wymiany maszynowej, ale nie do wyświetlania użytkownikowi.

Do formatowania czytelnego dla człowieka używaj toDays(), toHours(), toMinutes(), toSeconds() z ręcznym składaniem ciągu. Na przykład: „${days} d ${hours} g ${minutes} min”. Zwóć uwagę, że toHours() zwraca całkowitą liczbę godzin, a nie godziny w ciągu dnia.

Do podziału Duration na komponenty używa się wzoru: val hours = duration.toHours(); val minutes = duration.toMinutes() % 60; val seconds = duration.seconds % 60. Według Apache Commons Lang (2024), biblioteka DurationFormatUtils udostępnia dodatkowe możliwości formatowania.

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

Typowe błędy

Pierwszy błąd — pomylenie Duration i Period podczas pracy z datami. Duration mierzy sekundy, więc Duration.ofDays(1) to zawsze 24 godziny (86400 sekund), niezależnie od zmiany czasu na letni. Jeśli potrzebujesz dnia kalendarzowego, użyj Period.ofDays(1).

Drugi błąd — utrata nanosekund podczas konwersji. Duration może przechowywać nanosekundy, ale toMillis() i toSeconds() je odrzucają. Do dokładnych obliczeń używaj toNanos() lub pracuj z Duration bezpośrednio, bez konwersji na typy prymitywne.

Trzeci błąd — ignorowanie ujemnych Duration. Duration.between(start, end) zwraca start - end. Jeśli start jest po end, Duration będzie ujemna. Metoda abs() pomaga uzyskać wartość bezwzględną, a isNegative() — sprawdzić kolejność argumentów.

Czwarty błąd — nieprawidłowe formatowanie Duration dla UI. Duration.toString() zwraca ISO-8601, który jest nieczytelny. Zawsze formatuj Duration ręcznie do wyświetlenia użytkownikowi, używając toHours(), toMinutes() i toSeconds() z prawidłową resztą z dzielenia.

Często zadawane pytania

Czy Duration może być ujemne?

Tak, Duration może być ujemne. Duration.between(start, end) zwraca start - end. Jeśli start jest po end, Duration będzie ujemna. Użyj abs() aby uzyskać wartość bezwzględną lub isNegative() do sprawdzenia.

Jak dodać dwie Duration?

Użyj metody plus(Duration) lub operatora + w Kotlinie: duration1 + duration2. Wynik — nowa Duration. Metoda minus(Duration) odejmuje jedną długość od drugiej. Wszystkie operacje są niemutowalne i zwracają nowy obiekt.

Czym różni się Duration.ofDays(1) od Period.ofDays(1)?

Duration.ofDays(1) to zawsze 24 godziny (86400 sekund). Period.ofDays(1) to 1 dzień kalendarzowy, który przy DST może mieć 23 lub 25 godzin. Do obliczeń z dokładnym czasem używaj Duration, do kalendarzowych — Period.

Jak przekonwertować Duration na milisekundy?

Użyj metody toMillis(). Zwraca long — liczbę milisekund w Duration. Dla nanosekund użyj toNanos(). Uwaga: toNanos() może przekroczyć zakres long przy wartościach > 292 lat. Dla dużych Duration używaj toSeconds() lub toMinutes().

Jak obliczyć Duration między dwoma LocalTime?

Użyj Duration.between(startTime, endTime). Jeśli endTime jest mniejsze niż startTime (zmiana nocna), Duration będzie ujemna. Dodaj 24 godziny: duration.plusHours(24), jeśli zakładasz, że endTime to następny dzień.

Podsumowanie

  • Duration — niemutowalna klasa do pomiaru czasu trwania opartego na czasie z dokładnością do nanosekund, idealna do mierzenia interwałów.
  • Główna różnica od Period — Duration mierzy sekundy (czas fizyczny), Period — jednostki kalendarzowe.
  • Tworzona przez Duration.between() dla różnicy między momentami lub przez statyczne fabryki ofMinutes, ofHours, ofDays.
  • Obsługuje arytmetykę: plus, minus, multipliedBy, dividedBy, a także porównanie przez Comparable i abs.
  • W Androidzie Duration jest stosowane do obliczania timeoutów, interwałów synchronizacji, timerów i pomiaru wydajności.
  • Przy wyświetlaniu użytkownikowi formatuj Duration ręcznie — toString() zwraca ISO-8601, nieczytelny dla człowieka.
  • Pamiętaj, że Duration może być ujemne — sprawdzaj isNegative() i używaj abs() do poprawnych obliczeń.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również