66package kotlinx.datetime.test
77
88import kotlinx.datetime.*
9+ import kotlin.math.*
10+ import kotlin.random.*
911import kotlin.test.*
1012
1113class LocalTimeTest {
12-
14+
1315 @Test
1416 fun localTimeParsing () {
1517 fun checkParsedComponents (value : String , hour : Int , minute : Int , second : Int , nanosecond : Int ) {
@@ -63,7 +65,8 @@ class LocalTimeTest {
6365 Pair (LocalTime (0 , 0 , 0 , 9999 ), " 00:00:00.000009999" ),
6466 Pair (LocalTime (0 , 0 , 0 , 999 ), " 00:00:00.000000999" ),
6567 Pair (LocalTime (0 , 0 , 0 , 99 ), " 00:00:00.000000099" ),
66- Pair (LocalTime (0 , 0 , 0 , 9 ), " 00:00:00.000000009" ))
68+ Pair (LocalTime (0 , 0 , 0 , 9 ), " 00:00:00.000000009" ),
69+ )
6770 for ((time, str) in data) {
6871 assertEquals(str, time.toString())
6972 assertEquals(time, LocalTime .parse(str))
@@ -89,9 +92,18 @@ class LocalTimeTest {
8992 0L to LocalTime (0 , 0 ),
9093 5000000001L to LocalTime (0 , 0 , 5 , 1 ),
9194 44105123456789L to LocalTime (12 , 15 , 5 , 123456789 ),
92- 86399999999999L to LocalTime (23 , 59 , 59 , 999999999 ),
93- )
94-
95+ NANOS_PER_DAY - 1 to LocalTime (23 , 59 , 59 , 999999999 ),
96+ ) + buildMap {
97+ repeat(STRESS_TEST_ITERATIONS ) {
98+ val hour = Random .nextInt(24 )
99+ val minute = Random .nextInt(60 )
100+ val second = Random .nextInt(60 )
101+ val nanosecond = Random .nextInt(1_000_000_000 )
102+ val nanosecondOfDay =
103+ hour * NANOS_PER_HOUR + minute * NANOS_PER_MINUTE + second * NANOS_PER_ONE .toLong() + nanosecond
104+ put(nanosecondOfDay, LocalTime (hour, minute, second, nanosecond))
105+ }
106+ }
95107 data.forEach { (nanosecondOfDay, localTime) ->
96108 assertEquals(nanosecondOfDay, localTime.toNanosecondOfDay())
97109 assertEquals(localTime, LocalTime .fromNanosecondOfDay(nanosecondOfDay))
@@ -101,30 +113,69 @@ class LocalTimeTest {
101113 @Test
102114 fun fromNanosecondOfDayInvalid () {
103115 assertFailsWith<IllegalArgumentException > { LocalTime .fromNanosecondOfDay(- 1 ) }
104- assertFailsWith<IllegalArgumentException > { LocalTime .fromNanosecondOfDay(86400000000000L ) }
105- assertFailsWith<IllegalArgumentException > { LocalTime .fromNanosecondOfDay(Long .MAX_VALUE ) }
116+ assertFailsWith<IllegalArgumentException > { LocalTime .fromNanosecondOfDay(NANOS_PER_DAY ) }
117+ repeat(STRESS_TEST_ITERATIONS ) {
118+ assertFailsWith<IllegalArgumentException > {
119+ LocalTime .fromNanosecondOfDay(NANOS_PER_DAY + Random .nextLong().absoluteValue)
120+ }
121+ }
106122 }
107123
108124 @Test
109- fun fromSecondOfDay () {
125+ fun fromMillisecondOfDay () {
110126 val data = mapOf (
111127 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- )
128+ 5001 to LocalTime (0 , 0 , 5 , 1000000 ),
129+ 44105123 to LocalTime (12 , 15 , 5 , 123000000 ),
130+ MILLIS_PER_DAY - 1 to LocalTime (23 , 59 , 59 , 999000000 ),
131+ ) + buildMap {
132+ repeat(STRESS_TEST_ITERATIONS ) {
133+ val hour = Random .nextInt(24 )
134+ val minute = Random .nextInt(60 )
135+ val second = Random .nextInt(60 )
136+ val millisecond = Random .nextInt(1000 )
137+ val millisecondOfDay =
138+ (hour * SECONDS_PER_HOUR + minute * SECONDS_PER_MINUTE + second) * MILLIS_PER_ONE +
139+ millisecond
140+ put(millisecondOfDay, LocalTime (hour, minute, second, millisecond * NANOS_PER_MILLI ))
141+ }
142+ }
143+ data.forEach { (millisecondOfDay, localTime) ->
144+ assertEquals(millisecondOfDay, localTime.toMillisecondOfDay())
145+ assertEquals(localTime, LocalTime .fromMillisecondOfDay(millisecondOfDay))
146+ }
147+ }
116148
117- data.forEach { (secondOfDay, localTime) ->
118- assertEquals(secondOfDay, localTime.toSecondOfDay())
119- assertEquals(localTime, LocalTime .fromSecondOfDay(secondOfDay))
149+ @Test
150+ fun fromMillisecondOfDayInvalid () {
151+ assertFailsWith<IllegalArgumentException > { LocalTime .fromMillisecondOfDay(- 1 ) }
152+ assertFailsWith<IllegalArgumentException > { LocalTime .fromMillisecondOfDay(MILLIS_PER_DAY ) }
153+ repeat(STRESS_TEST_ITERATIONS ) {
154+ assertFailsWith<IllegalArgumentException > {
155+ LocalTime .fromMillisecondOfDay(MILLIS_PER_DAY + Random .nextInt().absoluteValue)
156+ }
157+ }
158+ }
159+
160+ @Test
161+ fun fromSecondOfDay () {
162+ var t = LocalTime (0 , 0 , 0 , 0 )
163+ for (i in 0 until SECONDS_PER_DAY ) {
164+ assertEquals(i, t.toSecondOfDay())
165+ assertEquals(t, LocalTime .fromSecondOfDay(t.toSecondOfDay()))
166+ t = t.plusSeconds(1 )
120167 }
121168 }
122169
123170 @Test
124171 fun fromSecondOfDayInvalid () {
125172 assertFailsWith<IllegalArgumentException > { LocalTime .fromSecondOfDay(- 1 ) }
126- assertFailsWith<IllegalArgumentException > { LocalTime .fromSecondOfDay(86400 ) }
127- assertFailsWith<IllegalArgumentException > { LocalTime .fromSecondOfDay(Int .MAX_VALUE ) }
173+ assertFailsWith<IllegalArgumentException > { LocalTime .fromSecondOfDay(SECONDS_PER_DAY ) }
174+ repeat(STRESS_TEST_ITERATIONS ) {
175+ assertFailsWith<IllegalArgumentException > {
176+ LocalTime .fromSecondOfDay(SECONDS_PER_DAY + Random .nextInt().absoluteValue)
177+ }
178+ }
128179 }
129180
130181 @Test
@@ -166,3 +217,18 @@ fun checkEquals(expected: LocalTime, actual: LocalTime) {
166217 assertEquals(expected.hashCode(), actual.hashCode())
167218 assertEquals(expected.toString(), actual.toString())
168219}
220+
221+ private fun LocalTime.plusSeconds (secondsToAdd : Long ): LocalTime {
222+ if (secondsToAdd == 0L ) {
223+ return this
224+ }
225+ val sofd: Int = hour * SECONDS_PER_HOUR + minute * SECONDS_PER_MINUTE + second
226+ val newSofd: Int = ((secondsToAdd % SECONDS_PER_DAY ).toInt() + sofd + SECONDS_PER_DAY ) % SECONDS_PER_DAY
227+ if (sofd == newSofd) {
228+ return this
229+ }
230+ val newHour: Int = newSofd / SECONDS_PER_HOUR
231+ val newMinute: Int = newSofd / SECONDS_PER_MINUTE % MINUTES_PER_HOUR
232+ val newSecond: Int = newSofd % SECONDS_PER_MINUTE
233+ return LocalTime (newHour, newMinute, newSecond, nanosecond)
234+ }
0 commit comments