Skip to content

Commit d686d81

Browse files
authored
Add LocalTime#toSecondOfDay & LocalTime.fromSecondOfDay (#204)
1 parent 9d4db54 commit d686d81

File tree

5 files changed

+119
-13
lines changed

5 files changed

+119
-13
lines changed

core/common/src/LocalTime.kt

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,20 @@ public expect class LocalTime : Comparable<LocalTime> {
4040
*/
4141
public fun parse(isoString: String): LocalTime
4242

43+
/**
44+
* Returns a LocalTime with the specified [secondOfDay]. The nanosecond field will be set to zero.
45+
*
46+
* @throws IllegalArgumentException if the boundaries of [secondOfDay] are exceeded.
47+
*/
48+
public fun fromSecondOfDay(secondOfDay: Int): LocalTime
49+
50+
/**
51+
* Returns a LocalTime with the specified [nanosecondOfDay].
52+
*
53+
* @throws IllegalArgumentException if the boundaries of [nanosecondOfDay] are exceeded.
54+
*/
55+
public fun fromNanosecondOfDay(nanosecondOfDay: Long): LocalTime
56+
4357
internal val MIN: LocalTime
4458
internal val MAX: LocalTime
4559
}
@@ -66,6 +80,12 @@ public expect class LocalTime : Comparable<LocalTime> {
6680
/** Returns the nanosecond-of-second time component of this time value. */
6781
public val nanosecond: Int
6882

83+
/** Returns the time as a second of a day, from 0 to 24 * 60 * 60 - 1. */
84+
public fun toSecondOfDay(): Int
85+
86+
/** Returns the time as a nanosecond of a day, from 0 to 24 * 60 * 60 * 1_000_000_000 - 1. */
87+
public fun toNanosecondOfDay(): Long
88+
6989
/**
7090
* Compares `this` time value with the [other] time value.
7191
* Returns zero if this value is equal to the other, a negative number if this value occurs earlier
@@ -110,4 +130,4 @@ public fun LocalTime.atDate(year: Int, month: Month, dayOfMonth: Int = 0): Local
110130
/**
111131
* Combines this time's components with the specified [LocalDate] components into a [LocalDateTime] value.
112132
*/
113-
public fun LocalTime.atDate(date: LocalDate): LocalDateTime = LocalDateTime(date, this)
133+
public fun LocalTime.atDate(date: LocalDate): LocalDateTime = LocalDateTime(date, this)

core/common/test/LocalTimeTest.kt

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
package kotlinx.datetime.test
77

88
import kotlinx.datetime.*
9-
import kotlinx.datetime.Clock
10-
import kotlin.math.min
119
import kotlin.test.*
1210

1311
class LocalTimeTest {
@@ -85,6 +83,58 @@ class LocalTimeTest {
8583
assertFailsWith<IllegalArgumentException> { LocalTime(0, 0, 0, 1_000_000_000) }
8684
}
8785

86+
@Test
87+
fun fromNanosecondOfDay() {
88+
val data = mapOf(
89+
0L to LocalTime(0, 0),
90+
5000000001L to LocalTime(0, 0, 5, 1),
91+
44105123456789L to LocalTime(12, 15, 5, 123456789),
92+
86399999999999L to LocalTime(23, 59, 59, 999999999),
93+
)
94+
95+
data.forEach { (nanosecondOfDay, localTime) ->
96+
assertEquals(nanosecondOfDay, localTime.toNanosecondOfDay())
97+
assertEquals(localTime, LocalTime.fromNanosecondOfDay(nanosecondOfDay))
98+
}
99+
}
100+
101+
@Test
102+
fun fromNanosecondOfDayInvalid() {
103+
assertFailsWith<IllegalArgumentException> { LocalTime.fromNanosecondOfDay(-1) }
104+
assertFailsWith<IllegalArgumentException> { LocalTime.fromNanosecondOfDay(86400000000000L) }
105+
assertFailsWith<IllegalArgumentException> { LocalTime.fromNanosecondOfDay(Long.MAX_VALUE) }
106+
}
107+
108+
@Test
109+
fun fromSecondOfDay() {
110+
val data = mapOf(
111+
0 to LocalTime(0, 0),
112+
5 to LocalTime(0, 0, 5),
113+
44105 to LocalTime(12, 15, 5),
114+
86399 to LocalTime(23, 59, 59),
115+
)
116+
117+
data.forEach { (secondOfDay, localTime) ->
118+
assertEquals(secondOfDay, localTime.toSecondOfDay())
119+
assertEquals(localTime, LocalTime.fromSecondOfDay(secondOfDay))
120+
}
121+
}
122+
123+
@Test
124+
fun fromSecondOfDayInvalid() {
125+
assertFailsWith<IllegalArgumentException> { LocalTime.fromSecondOfDay(-1) }
126+
assertFailsWith<IllegalArgumentException> { LocalTime.fromSecondOfDay(86400) }
127+
assertFailsWith<IllegalArgumentException> { LocalTime.fromSecondOfDay(Int.MAX_VALUE) }
128+
}
129+
130+
@Test
131+
fun fromSecondOfDayIgnoresNanosecond() {
132+
assertEquals(
133+
0,
134+
LocalTime(0, 0, 0, 100).toSecondOfDay(),
135+
)
136+
}
137+
88138
@Test
89139
fun atDate() {
90140
val time = LocalTime(12, 1, 59)

core/js/src/LocalTime.kt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ public actual class LocalTime internal constructor(internal val value: jtLocalTi
2626
public actual val minute: Int get() = value.minute().toInt()
2727
public actual val second: Int get() = value.second().toInt()
2828
public actual val nanosecond: Int get() = value.nano().toInt()
29+
public actual fun toSecondOfDay(): Int = value.toSecondOfDay().toInt()
30+
public actual fun toNanosecondOfDay(): Long = value.toNanoOfDay().toLong()
2931

3032
override fun equals(other: Any?): Boolean =
3133
(this === other) || (other is LocalTime && this.value == other.value)
@@ -44,7 +46,19 @@ public actual class LocalTime internal constructor(internal val value: jtLocalTi
4446
throw e
4547
}
4648

49+
public actual fun fromSecondOfDay(secondOfDay: Int): LocalTime = try {
50+
jtLocalTime.ofSecondOfDay(secondOfDay, 0).let(::LocalTime)
51+
} catch (e: Throwable) {
52+
throw IllegalArgumentException(e)
53+
}
54+
55+
public actual fun fromNanosecondOfDay(nanosecondOfDay: Long): LocalTime = try {
56+
jtLocalTime.ofNanoOfDay(nanosecondOfDay).let(::LocalTime)
57+
} catch (e: Throwable) {
58+
throw IllegalArgumentException(e)
59+
}
60+
4761
internal actual val MIN: LocalTime = LocalTime(jtLocalTime.MIN)
4862
internal actual val MAX: LocalTime = LocalTime(jtLocalTime.MAX)
4963
}
50-
}
64+
}

core/jvm/src/LocalTime.kt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ public actual class LocalTime internal constructor(internal val value: jtLocalTi
2929
public actual val minute: Int get() = value.minute
3030
public actual val second: Int get() = value.second
3131
public actual val nanosecond: Int get() = value.nano
32+
public actual fun toSecondOfDay(): Int = value.toSecondOfDay()
33+
public actual fun toNanosecondOfDay(): Long = value.toNanoOfDay()
3234

3335
override fun equals(other: Any?): Boolean =
3436
(this === other) || (other is LocalTime && this.value == other.value)
@@ -46,7 +48,19 @@ public actual class LocalTime internal constructor(internal val value: jtLocalTi
4648
throw DateTimeFormatException(e)
4749
}
4850

51+
public actual fun fromSecondOfDay(secondOfDay: Int): LocalTime = try {
52+
jtLocalTime.ofSecondOfDay(secondOfDay.toLong()).let(::LocalTime)
53+
} catch (e: DateTimeException) {
54+
throw IllegalArgumentException(e)
55+
}
56+
57+
public actual fun fromNanosecondOfDay(nanosecondOfDay: Long): LocalTime = try {
58+
jtLocalTime.ofNanoOfDay(nanosecondOfDay).let(::LocalTime)
59+
} catch (e: DateTimeException) {
60+
throw IllegalArgumentException(e)
61+
}
62+
4963
internal actual val MIN: LocalTime = LocalTime(jtLocalTime.MIN)
5064
internal actual val MAX: LocalTime = LocalTime(jtLocalTime.MAX)
5165
}
52-
}
66+
}

core/native/src/LocalTime.kt

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ public actual class LocalTime actual constructor(
6262
public actual fun parse(isoString: String): LocalTime =
6363
localTimeParser.parse(isoString)
6464

65+
public actual fun fromSecondOfDay(secondOfDay: Int): LocalTime =
66+
ofSecondOfDay(secondOfDay, 0)
67+
68+
public actual fun fromNanosecondOfDay(nanosecondOfDay: Long): LocalTime =
69+
ofNanoOfDay(nanosecondOfDay)
70+
6571
// org.threeten.bp.LocalTime#ofSecondOfDay(long, int)
6672
internal fun ofSecondOfDay(secondOfDay: Int, nanoOfSecond: Int): LocalTime {
6773
// Unidiomatic code due to https://github.com/Kotlin/kotlinx-datetime/issues/5
@@ -117,6 +123,16 @@ public actual class LocalTime actual constructor(
117123
return (nod xor (nod ushr 32)).toInt()
118124
}
119125

126+
// org.threeten.bp.LocalTime#toSecondOfDay
127+
public actual fun toSecondOfDay(): Int {
128+
var total: Int = hour * SECONDS_PER_HOUR
129+
total += minute * SECONDS_PER_MINUTE
130+
total += second
131+
return total
132+
}
133+
134+
public actual fun toNanosecondOfDay(): Long = toNanoOfDay()
135+
120136
// org.threeten.bp.LocalTime#toNanoOfDay
121137
internal fun toNanoOfDay(): Long {
122138
var total: Long = hour.toLong() * NANOS_PER_ONE * SECONDS_PER_HOUR
@@ -126,14 +142,6 @@ public actual class LocalTime actual constructor(
126142
return total
127143
}
128144

129-
// org.threeten.bp.LocalTime#toSecondOfDay
130-
internal fun toSecondOfDay(): Int {
131-
var total: Int = hour * SECONDS_PER_HOUR
132-
total += minute * SECONDS_PER_MINUTE
133-
total += second
134-
return total
135-
}
136-
137145
// org.threeten.bp.LocalTime#toString
138146
actual override fun toString(): String {
139147
val buf = StringBuilder(18)

0 commit comments

Comments
 (0)