[go: nahoru, domu]

blob: 305adf9949f1e691513a69274678036359899331 [file] [log] [blame]
/*
* Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:kotlin.jvm.JvmName("Durations")
@file:Suppress("NOTHING_TO_INLINE")
package androidx.compose.ui.unit
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
/*
* The following unit conversion factors are required to be public due to their use
* from inline functions.
*/
const val NanosecondsPerMicrosecond = 1000L
const val MicrosecondsPerMillisecond = 1000L
const val MillisecondsPerSecond = 1000L
const val SecondsPerMinute = 60L
const val MinutesPerHour = 60L
const val HoursPerDay = 24L
// TODO(mount): these should be "const val", but that doesn't work right
// now with the IR compiler.
val NanosecondsPerMillisecond = NanosecondsPerMicrosecond * MicrosecondsPerMillisecond
val NanosecondsPerSecond = NanosecondsPerMillisecond * MillisecondsPerSecond
val NanosecondsPerMinute = NanosecondsPerSecond * SecondsPerMinute
val NanosecondsPerHour = NanosecondsPerMinute * MinutesPerHour
val NanosecondsPerDay = NanosecondsPerHour * HoursPerDay
/** Only used by this implementation */
private const val MicrosecondsPerSecond = MicrosecondsPerMillisecond * MillisecondsPerSecond
/**
* Constructs a [Duration] given a series of time intervals in different units.
*/
fun Duration(
days: Long = 0,
hours: Long = 0,
minutes: Long = 0,
seconds: Long = 0,
milliseconds: Long = 0,
microseconds: Long = 0,
nanoseconds: Long = 0
) = Duration(
days * NanosecondsPerDay +
hours * NanosecondsPerHour +
minutes * NanosecondsPerMinute +
seconds * NanosecondsPerSecond +
milliseconds * NanosecondsPerMillisecond +
microseconds * NanosecondsPerMicrosecond +
nanoseconds
)
/* A [Duration] of this many days. */
// TODO(inline)
val Long.days: Duration get() = Duration(this * NanosecondsPerDay)
/* A [Duration] of this many hours. */
// TODO(inline)
val Long.hours: Duration get() = Duration(this * NanosecondsPerHour)
/* A [Duration] of this many minutes. */
// TODO(inline)
val Long.minutes: Duration get() = Duration(this * NanosecondsPerMinute)
/* A [Duration] of this many seconds. */
// TODO(inline)
val Long.seconds: Duration get() = Duration(this * NanosecondsPerSecond)
/* A [Duration] of this many milliseconds. */
// TODO(inline)
val Long.milliseconds: Duration get() = Duration(this * NanosecondsPerMillisecond)
/* A [Duration] of this many microseconds. */
// TODO(inline)
val Long.microseconds: Duration get() = Duration(this * NanosecondsPerMicrosecond)
/* A [Duration] of this many nanoseconds. */
// TODO(inline)
val Long.nanoseconds: Duration get() = Duration(this)
/* A [Duration] of this many days. */
// TODO(inline)
val Int.days: Duration get() = toLong().days
/* A [Duration] of this many hours. */
// TODO(inline)
val Int.hours: Duration get() = toLong().hours
/* A [Duration] of this many minutes. */
// TODO(inline)
val Int.minutes: Duration get() = toLong().minutes
/* A [Duration] of this many seconds. */
// TODO(inline)
val Int.seconds: Duration get() = toLong().seconds
/* A [Duration] of this many milliseconds. */
// TODO(inline)
val Int.milliseconds: Duration get() = toLong().milliseconds
/* A [Duration] of this many microseconds. */
// TODO(inline)
val Int.microseconds: Duration get() = toLong().microseconds
/* A [Duration] of this many nanoseconds. */
// TODO(inline)
val Int.nanoseconds: Duration get() = toLong().nanoseconds
/**
* A span of time, such as 27 days, 4 hours, 12 minutes, and 3 seconds.
*
* A [Duration] represents a difference from one point in time to another. The
* duration may be "negative" if the difference is from a later time to an
* earlier.
*
* Durations are context independent. For example, a duration of 2 days is
* always 48 hours, even when it is added to a `DateTime` just when the
* time zone is about to do a daylight-savings switch.
*
* Despite the same name, a [Duration] object does not implement "Durations"
* as specified by ISO 8601. In particular, a duration object does not keep
* track of the individually provided members (such as "days" or "hours"), but
* only uses these arguments to compute the length of the corresponding time
* interval.
*
* To create a [Duration], use the unit extension functions on the primitive
* `Int` and `Long` types:
*
* val aLongWeekend = 96.hours
*
* To create a [Duration] from several components, use the [Duration] factory function:
*
* val fastestMarathon = Duration(hours = 2, minutes = 3, seconds = 2)
*
* The [Duration] is the sum of all individual parts.
* This means that individual parts can be larger than the next-bigger unit.
* For example, [inMinutes] can be greater than 59.
*
* assertEquals(123, fastestMarathon.inMinutes)
*
* All individual parts are allowed to be negative.
*
* Use one of the extensions such as [inDays] to retrieve the integer value of the Duration
* in the specified time unit. Note that the returned value is rounded down.
* For example,
*
* val aLongWeekend = 86.hours
* assertEquals(3, aLongWeekend.inDays())
*/
@Immutable
data class Duration(val nanoseconds: Long) : Comparable<Duration> {
/**
* Adds this Duration and [other] and returns the sum as a Duration.
*/
@Stable
operator fun plus(other: Duration) = Duration(nanoseconds + other.nanoseconds)
/**
* Subtracts [other] from this Duration and returns the difference.
*/
@Stable
operator fun minus(other: Duration) = Duration(nanoseconds - other.nanoseconds)
/**
* Multiplies this Duration by the given [factor] and returns the result.
*/
@Stable
operator fun times(factor: Int) = Duration(nanoseconds * factor)
/**
* Multiplies this Duration by the given [factor] and returns the result.
*/
@Stable
operator fun times(factor: Double) = Duration((nanoseconds * factor).toLong())
/**
* Divides this Duration by the given [quotient] and returns the truncated
* result as a Duration.
*/
@Stable
operator fun div(quotient: Int) = Duration(nanoseconds / quotient)
/**
* Divides this Duration by the given [quotient] and returns the truncated
* result as a Duration.
*/
@Stable
operator fun div(quotient: Double) = Duration((nanoseconds / quotient).toLong())
/**
* Compares this Duration to [other], returning zero if the values are equal.
*
* Returns a negative integer if this [Duration] is shorter than
* [other], or a positive integer if it is longer.
*
* A negative [Duration] is always considered shorter than a positive one.
*
* It is always the case that `duration1.compareTo(duration2) < 0` if
* `(someDate + duration1).compareTo(someDate + duration2) < 0`.
*/
@Stable
override fun compareTo(other: Duration): Int = when {
nanoseconds < other.nanoseconds -> -1
nanoseconds == other.nanoseconds -> 0
else -> 1
}
/**
* Returns a string representation of this [Duration].
*
* Returns a string with hours, minutes, seconds, and microseconds, in the
* following format: `HH:MM:SS.mmmmmm`. For example,
*
* val d = Duration(days = 1, hours = 1, minutes = 33, microseconds = 500)
* d.toString() // "25:33:00.000500"
*/
@Stable
override fun toString(): String {
if (inMicroseconds() < 0) {
return "-${Duration(-nanoseconds)}"
}
val twoDigitMinutes = inMinutes().rem(MinutesPerHour).toString().padStart(2, '0')
val twoDigitSeconds = inSeconds().rem(SecondsPerMinute).toString().padStart(2, '0')
val sixDigitUs = inMicroseconds().rem(MicrosecondsPerSecond).toString().padStart(6, '0')
return "${inHours()}:$twoDigitMinutes:$twoDigitSeconds.$sixDigitUs"
}
companion object {
/** An empty Duration. No delay. Instant. */
@Stable
val Zero = Duration(0)
}
}
/*
* API note: The `inUnits()` functions below are not `toUnits()` because they do not
* perform type conversion. They are also functions rather than properties to highlight
* that they are truncating conversions of the whole value, not hours/minutes-style components
* isolated from each other available unit.
*/
/**
* Returns the number of whole days spanned by this Duration.
*/
// TODO(inline)
fun Duration.inDays(): Long = nanoseconds / NanosecondsPerDay
/**
* Returns the number of whole hours spanned by this Duration.
*
* The returned value can be greater than 23.
*/
// TODO(inline)
fun Duration.inHours(): Long = nanoseconds / NanosecondsPerHour
/**
* Returns the number of whole minutes spanned by this Duration.
*
* The returned value can be greater than 59.
*/
// TODO(inline)
fun Duration.inMinutes(): Long = nanoseconds / NanosecondsPerMinute
/**
* Returns the number of whole seconds spanned by this Duration.
*
* The returned value can be greater than 59.
*/
// TODO(inline)
fun Duration.inSeconds(): Long = nanoseconds / NanosecondsPerSecond
/**
* Returns number of whole milliseconds spanned by this Duration.
*
* The returned value can be greater than 999.
*/
// TODO(inline)
fun Duration.inMilliseconds(): Long = nanoseconds / NanosecondsPerMillisecond
/**
* Returns number of whole microseconds spanned by this Duration.
*/
// TODO(inline)
fun Duration.inMicroseconds(): Long = nanoseconds / NanosecondsPerMicrosecond