commonMain.io.islandtime.OffsetTime.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of core-metadata Show documentation
Show all versions of core-metadata Show documentation
A multiplatform library for working with dates and times
package io.islandtime
import io.islandtime.measures.*
import io.islandtime.parser.*
/**
* A time of day with an offset from UTC.
*/
class OffsetTime(
/** The time of day. */
val time: Time,
/** The offset from UTC. */
val offset: UtcOffset
) {
init {
offset.validate()
}
/**
* Create an [OffsetTime].
* @throws DateTimeException if the time or offset is invalid
*/
constructor(
hour: Int,
minute: Int,
second: Int = 0,
nanosecond: Int = 0,
offset: UtcOffset
) : this(Time(hour, minute, second, nanosecond), offset)
/**
* The hour of the day.
*/
inline val hour: Int get() = time.hour
/**
* The minute of the hour.
*/
inline val minute: Int get() = time.minute
/**
* The second of the minute.
*/
inline val second: Int get() = time.second
/**
* The nanosecond of the second.
*/
inline val nanosecond: Int get() = time.nanosecond
/**
* The number of nanoseconds since the start of the day, but normalized to a UTC offset of zero, allowing
* [OffsetTime] objects with different offsets to be compared.
*/
val nanosecondsSinceStartOfUtcDay: LongNanoseconds
get() = (time.nanosecondsSinceStartOfDay.value - offset.totalSeconds.inNanoseconds.value).nanoseconds
/**
* Return an [OffsetTime] with the offset changed to [newOffset], adjusting the time component such that the instant
* remains the same.
*/
fun adjustedTo(newOffset: UtcOffset): OffsetTime {
return if (newOffset == offset) {
this
} else {
val newTime = time + (newOffset.totalSeconds - offset.totalSeconds)
OffsetTime(newTime, newOffset)
}
}
operator fun plus(duration: Duration) = copy(time = time + duration)
operator fun plus(hours: LongHours) = copy(time = time + hours)
operator fun plus(hours: IntHours) = copy(time = time + hours)
operator fun plus(minutes: LongMinutes) = copy(time = time + minutes)
operator fun plus(minutes: IntMinutes) = copy(time = time + minutes)
operator fun plus(seconds: LongSeconds) = copy(time = time + seconds)
operator fun plus(seconds: IntSeconds) = copy(time = time + seconds)
operator fun plus(milliseconds: LongMilliseconds) = copy(time = time + milliseconds)
operator fun plus(milliseconds: IntMilliseconds) = copy(time = time + milliseconds)
operator fun plus(microseconds: LongMicroseconds) = copy(time = time + microseconds)
operator fun plus(microseconds: IntMicroseconds) = copy(time = time + microseconds)
operator fun plus(nanoseconds: LongNanoseconds) = copy(time = time + nanoseconds)
operator fun plus(nanoseconds: IntNanoseconds) = copy(time = time + nanoseconds)
operator fun minus(duration: Duration) = copy(time = time - duration)
operator fun minus(hours: LongHours) = copy(time = time - hours)
operator fun minus(hours: IntHours) = copy(time = time - hours)
operator fun minus(minutes: LongMinutes) = copy(time = time - minutes)
operator fun minus(minutes: IntMinutes) = copy(time = time - minutes)
operator fun minus(seconds: LongSeconds) = copy(time = time - seconds)
operator fun minus(seconds: IntSeconds) = copy(time = time - seconds)
operator fun minus(milliseconds: LongMilliseconds) = copy(time = time - milliseconds)
operator fun minus(milliseconds: IntMilliseconds) = copy(time = time - milliseconds)
operator fun minus(microseconds: LongMicroseconds) = copy(time = time - microseconds)
operator fun minus(microseconds: IntMicroseconds) = copy(time = time - microseconds)
operator fun minus(nanoseconds: LongNanoseconds) = copy(time = time - nanoseconds)
operator fun minus(nanoseconds: IntNanoseconds) = copy(time = time - nanoseconds)
/**
* Compare to another [OffsetTime] based on timeline order, ignoring offset differences.
* @see DEFAULT_SORT_ORDER
* @see TIMELINE_ORDER
*/
operator fun compareTo(other: OffsetTime): Int {
return nanosecondsSinceStartOfUtcDay.compareTo(other.nanosecondsSinceStartOfUtcDay)
}
override fun equals(other: Any?): Boolean {
return this === other || (other is OffsetTime && time == other.time && offset == other.offset)
}
override fun hashCode(): Int {
return 31 * time.hashCode() + offset.hashCode()
}
override fun toString(): String {
return buildString(MAX_OFFSET_TIME_STRING_LENGTH) { appendOffsetTime(this@OffsetTime) }
}
/**
* Return a copy of this [OffsetTime], replacing individual components with new values as desired.
*
* @throws DateTimeException if the resulting time or offset is invalid
*/
fun copy(
time: Time = this.time,
offset: UtcOffset = this.offset
) = OffsetTime(time, offset)
/**
* Return a copy of this [OffsetTime], replacing individual components with new values as desired.
*
* @throws DateTimeException if the resulting time or offset is invalid
*/
fun copy(
hour: Int = this.hour,
minute: Int = this.minute,
second: Int = this.second,
nanosecond: Int = this.nanosecond,
offset: UtcOffset = this.offset
) = OffsetTime(time.copy(hour, minute, second, nanosecond), offset)
companion object {
/**
* The smallest allowed [OffsetTime] -- `00:00+18:00`.
*/
val MIN = Time.MIN at UtcOffset.MAX
/**
* The largest allowed [OffsetTime] -- `23:59:59.999999999-18:00`.
*/
val MAX = Time.MAX at UtcOffset.MIN
/**
* Compare by UTC equivalent instant, then time. Using this `Comparator` guarantees a deterministic order when
* sorting.
*/
val DEFAULT_SORT_ORDER = compareBy { it.nanosecondsSinceStartOfUtcDay }.thenBy { it.time }
/**
* Compare by timeline order only, ignoring any offset differences.
*/
val TIMELINE_ORDER = compareBy { it.nanosecondsSinceStartOfUtcDay }
}
}
/**
* Combine a local time with a UTC offset to create an [OffsetTime].
*/
infix fun Time.at(offset: UtcOffset) = OffsetTime(this, offset)
/**
* Convert a string to an [OffsetTime].
*
* The string is assumed to be an ISO-8601 time with the UTC offset in extended format. For example, `02:30+01:00` or
* `14:40:23Z`. The output of [OffsetTime.toString] can be safely parsed using this method.
*
* @throws DateTimeParseException if parsing fails
* @throws DateTimeException if the parsed time or offset is invalid
*/
fun String.toOffsetTime() = toOffsetTime(DateTimeParsers.Iso.Extended.OFFSET_TIME)
/**
* Convert a string to an [OffsetTime] using a specific parser.
*
* A set of predefined parsers can be found in [DateTimeParsers].
*
* Any custom parser must be capable of supplying the fields necessary to resolve both a [Time] and [UtcOffset].
*
* @throws DateTimeParseException if parsing fails
* @throws DateTimeException if the parsed time or offset is invalid
*/
fun String.toOffsetTime(
parser: DateTimeParser,
settings: DateTimeParserSettings = DateTimeParserSettings.DEFAULT
): OffsetTime {
val result = parser.parse(this, settings)
return result.toOffsetTime() ?: throwParserFieldResolutionException(this)
}
internal fun DateTimeParseResult.toOffsetTime(): OffsetTime? {
val time = this.toTime()
val utcOffset = this.toUtcOffset()
return if (time != null && utcOffset != null) {
OffsetTime(time, utcOffset)
} else {
null
}
}
internal const val MAX_OFFSET_TIME_STRING_LENGTH = MAX_TIME_STRING_LENGTH + MAX_UTC_OFFSET_STRING_LENGTH
internal fun StringBuilder.appendOffsetTime(offsetTime: OffsetTime): StringBuilder {
with(offsetTime) {
appendTime(time)
appendUtcOffset(offset)
}
return this
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy