1. Introduction

While building software applications, dealing with time intervals and durations is a common task. With the Duration class, Kotlin provides a powerful API to handle this particular aspect of time management.

In this tutorial, we’ll look at the Duration class and how it makes handling time and duration operations effective and easy in Kotlin.

2. What Is Duration?

A Duration represents a specific amount of time that can be positive, negative, zero, or even infinite.

These intervals are specified through the DurationUnit enum, supporting the types DAYS, HOURS, MINUTES, SECONDS, MILLISECONDS, MICROSECONDS, and NANOSECONDS. Consequently, durations exceeding a day are expressed in days, even when referring to weeks and months.

The Duration class facilitates the creation, manipulation, aggregation, and conversion of durations.

Unlike dates and times that pinpoint specific moments, durations represent the amount of time that has passed between those moments. For example, Duration.DAYS expresses a length of time in whole days, with each day representing 24 hours. It focuses on the elapsed time itself, not a specific date.

The Duration class in Kotlin finds practical use in scenarios such as scheduling tasks, managing timeouts, measuring elapsed time, and performing time-based calculations with precision and efficiency.

3. Creating Durations

Kotlin provides multiple ways to create durations. Let’s look at different approaches in this section.

3.1. Using Companion Object

Kotlin defines simple extension functions in the Duration companion object to easily create durations from Int, Long, and Double. Let’s see how to use them:

val tenMinutes = 10.minutes 
val tenSeconds = 10.seconds
val tenHours = 10.hours
val tenDays = 10.days
val tenMillis = 10.milliseconds
val tenMicros = 10.microseconds
val tenNanos = 10.nanoseconds

Furthermore, we can also create zero and infinite durations:

val zero = Duration.ZERO
val infinite = Duration.INFINITE

An infinite duration is useful for configuring values such as timeouts that should never expire.

3.2. Using toDuration()

Another way of creating duration is using the toDuration() extension function on Int, Long, and Double by passing the required unit. Let’s look at the usage:

val tenMinutes = 10.toDuration(DurationUnit.MINUTES)
val tenSeconds = 10.toDuration(DurationUnit.SECONDS)

This function generates a duration based on the provided number and the unit specified by the DurationUnit enum value.

3.3. From ISO8601 Duration Format

We can also create a duration from ISO8601 duration format strings. In this format, durations can be represented using a period designator and its corresponding value. For instance, ten days can be denoted as P10D, where P marks the beginning of the period and 10D signifies ten days. Likewise, ten minutes can be represented as PT10M. Here, T indicates the start of the time part, and 10M denotes ten minutes. As there are no days involved in this representation, there are no values between P and T.

Let’s see how we can use this in Kotlin:

val tenMinDuration = Duration.parseIsoString("PT10M")
val tenDays = Duration.parseIsoString("P10D")
val tenDaysAndOneHour = Duration.parseIsoString("P10DT1H")
val tenDaysWithAllUnits = Duration.parseIsoString("P10DT1H5M7S")

These examples show how to convert different ISO8601 time expressions into Duration objects using the parseIsoString() method.

It’s important to note that in Kotlin, the maximum period designator for days is represented by D, even though the ISO8601 standard also supports Y for years and M for months.

4. Duration Operations

Duration offers a variety of operators for interacting with duration instances.

4.1. Conversion of Durations

We can retrieve values from the Duration in various units using methods like inWholeSeconds(), inWholeMinutes(), and more:

val tenMinutes = 10.minutes
assertEquals(10L, tenMinutes.inWholeMinutes)
assertEquals(600L, tenMinutes.inWholeSeconds)

Similarly, we can convert a Duration to an ISO8601 string format using the toIsoString() method:

val tenSeconds = 10.seconds 
assertEquals("PT10S", tenSeconds.toIsoString())
val tenDaysAndOneHour = Duration.parseIsoString("P10DT1H")
assertEquals("PT241H", tenDaysAndOneHour.toIsoString())

However, it’s worth noting that this method always utilizes the maximum hours in the converted values. The days are converted to hours and then used, thus omitting the D component. Consequently, when using toIsoString(), the method converts 10D into 240 hours.

Furthermore, we can extract the components of a duration into its units:

val seventyMinutes = 70.minutes
val asStr = seventyMinutes.toComponents { hrs, min, sec, nanos -> "${hrs}:${min}" }
assertEquals("1:10", asStr)

In the above example, the toComponents() method breaks down a duration into hours, minutes, seconds, and nanoseconds, allowing for effortless use of each component. Moreover, multiple toComponents() methods are available, each returning different units for added versatility.

4.2. Arithmetic Operations

Just like numeric values, we can combine multiple Duration instances. Different types of durations are automatically handled and converted correctly.

Let’s look at some examples:

val tenMinutes = 10.minutes
val fiveHours = 5.hours
val fiveHoursPlusTenMin = tenMinutes + fiveHours
assertEquals(310L, fiveHoursPlusTenMin.inWholeMinutes)
val fiveHoursMinusTenMin = fiveHours - tenMinutes
assertEquals(290L, fiveHoursMinusTenMin.inWholeMinutes)
val timesMinutes = tenMinutes.times(3)
assertEquals(30L, timesMinutes.inWholeMinutes)
val sixSecs = tenMinutes.div(100)
assertEquals(6, sixSecs.inWholeSeconds)

Additionally, instead of using the operators + and , we can achieve the same result using the functions plus() and minus().

These unified operations greatly simplify the process of working with durations of varying units.

4.3. Comparing Durations

Kotlin provides various methods to compare different durations. Let’s look at different ways to compare durations:

val tenMinutes = 10.minutes
val fiveHours = 5.hours
assertTrue { fiveHours > tenMinutes }
assertFalse { fiveHours < tenMinutes }
assertTrue { fiveHours == 300.minutes }

The example above shows different ways to compare Duration instances.

Furthermore, Kotlin offers a range of methods to verify different conditions, including isInfinite(), isNegative(), isFinite(), and more.

4.4. Duration Between Two DateTime

We can also create Duration from two DateTime instances:

val datetime1 = LocalDateTime.now()
val datetime2 = LocalDateTime.now().minusDays(1).minusHours(1)
val duration = java.time.Duration.between(datetime2, datetime1).toKotlinDuration()
val expectedDuration = 25.hours
assertEquals(expectedDuration, duration)

Here, we use the Duration API from the java.time package to create a duration value. However, this instance is from the Java API. We can convert it to a Kotlin Duration using the extension function toKotlinDuration().

4.5. Some Practical Uses

The Duration class has many practical applications when building software.

We can measure how long a method or a code block takes to execute:

@ExperimentalTime
fun main() {
    val elapsedTime = kotlin.time.measureTime {
        Thread.sleep(510)
    }
    println(elapsedTime)
}

In this example, the elapsedTime variable captures the duration taken for the code block to execute.

Similarly, coroutines use the duration value to specify a delayed execution:

@OptIn(ExperimentalTime::class)
fun main() = runBlocking {
    val delayDuration = 1000.milliseconds
    println("Task will execute after a delay of $delayDuration")
    delay(delayDuration)
    println("Task executed")
}

In this example, we delay the execution using the delay() function by passing the specified duration value.

5. Conclusion

In this article, we explored the Duration class in Kotlin and its various operations.

We discussed different ways to create and parse Durations*.* Furthermore, the Duration class offers various operations like adding, subtracting, comparing, and converting units. Whether performing calculations, scheduling tasks, or managing timeouts, Kotlin’s Duration class provides the essential tools to simplify time management tasks.

As always, the sample code used in this tutorial is available over on GitHub.