6
6
package kotlinx.datetime.test
7
7
8
8
import kotlinx.datetime.*
9
+ import kotlin.math.*
10
+ import kotlin.random.*
9
11
import kotlin.test.*
10
12
11
13
class LocalTimeTest {
12
-
14
+
13
15
@Test
14
16
fun localTimeParsing () {
15
17
fun checkParsedComponents (value : String , hour : Int , minute : Int , second : Int , nanosecond : Int ) {
@@ -63,7 +65,8 @@ class LocalTimeTest {
63
65
Pair (LocalTime (0 , 0 , 0 , 9999 ), " 00:00:00.000009999" ),
64
66
Pair (LocalTime (0 , 0 , 0 , 999 ), " 00:00:00.000000999" ),
65
67
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
+ )
67
70
for ((time, str) in data) {
68
71
assertEquals(str, time.toString())
69
72
assertEquals(time, LocalTime .parse(str))
@@ -89,9 +92,18 @@ class LocalTimeTest {
89
92
0L to LocalTime (0 , 0 ),
90
93
5000000001L to LocalTime (0 , 0 , 5 , 1 ),
91
94
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
+ }
95
107
data.forEach { (nanosecondOfDay, localTime) ->
96
108
assertEquals(nanosecondOfDay, localTime.toNanosecondOfDay())
97
109
assertEquals(localTime, LocalTime .fromNanosecondOfDay(nanosecondOfDay))
@@ -101,30 +113,69 @@ class LocalTimeTest {
101
113
@Test
102
114
fun fromNanosecondOfDayInvalid () {
103
115
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
+ }
106
122
}
107
123
108
124
@Test
109
- fun fromSecondOfDay () {
125
+ fun fromMillisecondOfDay () {
110
126
val data = mapOf (
111
127
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
+ }
116
148
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 )
120
167
}
121
168
}
122
169
123
170
@Test
124
171
fun fromSecondOfDayInvalid () {
125
172
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
+ }
128
179
}
129
180
130
181
@Test
@@ -166,3 +217,18 @@ fun checkEquals(expected: LocalTime, actual: LocalTime) {
166
217
assertEquals(expected.hashCode(), actual.hashCode())
167
218
assertEquals(expected.toString(), actual.toString())
168
219
}
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