6
6
package kotlinx.datetime.test
7
7
8
8
import kotlinx.datetime.*
9
+ import kotlinx.datetime.internal.*
9
10
import kotlin.random.*
10
11
import kotlin.test.*
11
12
@@ -36,8 +37,9 @@ class LocalDateTest {
36
37
37
38
@Test
38
39
fun parseIsoString () {
39
- fun checkParsedComponents (value : String , year : Int , month : Int , day : Int , dayOfWeek : Int , dayOfYear : Int ) {
40
+ fun checkParsedComponents (value : String , year : Int , month : Int , day : Int , dayOfWeek : Int? = null , dayOfYear : Int? = null ) {
40
41
checkComponents(LocalDate .parse(value), year, month, day, dayOfWeek, dayOfYear)
42
+ assertEquals(value, LocalDate (year, month, day).toString())
41
43
}
42
44
checkParsedComponents(" 2019-10-01" , 2019 , 10 , 1 , 2 , 274 )
43
45
checkParsedComponents(" 2016-02-29" , 2016 , 2 , 29 , 1 , 60 )
@@ -49,6 +51,17 @@ class LocalDateTest {
49
51
assertInvalidFormat { LocalDate .parse(" 2017-10--01" ) }
50
52
// this date is currently larger than the largest representable one any of the platforms:
51
53
assertInvalidFormat { LocalDate .parse(" +1000000000-10-01" ) }
54
+ // threetenbp
55
+ checkParsedComponents(" 2008-07-05" , 2008 , 7 , 5 )
56
+ checkParsedComponents(" 2007-12-31" , 2007 , 12 , 31 )
57
+ checkParsedComponents(" 0999-12-31" , 999 , 12 , 31 )
58
+ checkParsedComponents(" -0001-01-02" , - 1 , 1 , 2 )
59
+ checkParsedComponents(" 9999-12-31" , 9999 , 12 , 31 )
60
+ checkParsedComponents(" -9999-12-31" , - 9999 , 12 , 31 )
61
+ checkParsedComponents(" +10000-01-01" , 10000 , 1 , 1 )
62
+ checkParsedComponents(" -10000-01-01" , - 10000 , 1 , 1 )
63
+ checkParsedComponents(" +123456-01-01" , 123456 , 1 , 1 )
64
+ checkParsedComponents(" -123456-01-01" , - 123456 , 1 , 1 )
52
65
}
53
66
54
67
@Test
@@ -221,9 +234,61 @@ class LocalDateTest {
221
234
assertEquals(Int .MIN_VALUE , LocalDate .MAX .until(LocalDate .MIN , DateTimeUnit .DAY ))
222
235
}
223
236
}
224
- }
225
-
237
+ @Test
238
+ fun fromEpochDays () {
239
+ /* * This test uses [LocalDate.next] and [LocalDate.previous] and not [LocalDate.plus] because, on Native,
240
+ * [LocalDate.plus] is implemented via [LocalDate.toEpochDays]/[LocalDate.fromEpochDays], and so it's better to
241
+ * test those independently. */
242
+ if (LocalDate .fromEpochDays(0 ).daysUntil(LocalDate .MIN ) > Int .MIN_VALUE ) {
243
+ assertEquals(LocalDate .MIN , LocalDate .fromEpochDays(LocalDate .MIN .toEpochDays()))
244
+ assertFailsWith<IllegalArgumentException > { LocalDate .fromEpochDays(LocalDate .MIN .toEpochDays() - 1 ) }
245
+ assertFailsWith<IllegalArgumentException > { LocalDate .fromEpochDays(Int .MIN_VALUE ) }
246
+ }
247
+ if (LocalDate .fromEpochDays(0 ).daysUntil(LocalDate .MAX ) < Int .MAX_VALUE ) {
248
+ assertEquals(LocalDate .MAX , LocalDate .fromEpochDays(LocalDate .MAX .toEpochDays()))
249
+ assertFailsWith<IllegalArgumentException > { LocalDate .fromEpochDays(LocalDate .MAX .toEpochDays() + 1 ) }
250
+ assertFailsWith<IllegalArgumentException > { LocalDate .fromEpochDays(Int .MAX_VALUE ) }
251
+ }
252
+ val eraBeginning = - 678941 - 40587
253
+ assertEquals(LocalDate (1970 , 1 , 1 ), LocalDate .fromEpochDays(0 ))
254
+ assertEquals(LocalDate (0 , 1 , 1 ), LocalDate .fromEpochDays(eraBeginning))
255
+ assertEquals(LocalDate (- 1 , 12 , 31 ), LocalDate .fromEpochDays(eraBeginning - 1 ))
256
+ var test = LocalDate (0 , 1 , 1 )
257
+ for (i in eraBeginning.. 699999 ) {
258
+ assertEquals(test, LocalDate .fromEpochDays(i))
259
+ test = test.next
260
+ }
261
+ test = LocalDate (0 , 1 , 1 )
262
+ for (i in eraBeginning downTo - 2000000 + 1 ) {
263
+ assertEquals(test, LocalDate .fromEpochDays(i))
264
+ test = test.previous
265
+ }
266
+ }
226
267
268
+ // threetenbp
269
+ @Test
270
+ fun toEpochDays () {
271
+ /* * This test uses [LocalDate.next] and [LocalDate.previous] and not [LocalDate.plus] because, on Native,
272
+ * [LocalDate.plus] is implemented via [LocalDate.toEpochDays]/[LocalDate.fromEpochDays], and so it's better to
273
+ * test those independently. */
274
+ val startOfEra = - 678941 - 40587
275
+ var date = LocalDate (0 , 1 , 1 )
276
+ for (i in startOfEra.. 699999 ) {
277
+ assertEquals(i, date.toEpochDays())
278
+ date = date.next
279
+ }
280
+ date = LocalDate (0 , 1 , 1 )
281
+ for (i in startOfEra downTo - 2000000 + 1 ) {
282
+ assertEquals(i, date.toEpochDays())
283
+ date = date.previous
284
+ }
285
+ assertEquals(- 40587 , LocalDate (1858 , 11 , 17 ).toEpochDays())
286
+ assertEquals(- 678575 - 40587 , LocalDate (1 , 1 , 1 ).toEpochDays())
287
+ assertEquals(49987 - 40587 , LocalDate (1995 , 9 , 27 ).toEpochDays())
288
+ assertEquals(0 , LocalDate (1970 , 1 , 1 ).toEpochDays())
289
+ assertEquals(- 678942 - 40587 , LocalDate (- 1 , 12 , 31 ).toEpochDays())
290
+ }
291
+ }
227
292
228
293
fun checkInvalidDate (constructor : (year: Int , month: Int , day: Int ) -> LocalDate ) {
229
294
assertFailsWith<IllegalArgumentException > { constructor (2007 , 2 , 29 ) }
@@ -236,3 +301,22 @@ fun checkInvalidDate(constructor: (year: Int, month: Int, day: Int) -> LocalDate
236
301
assertFailsWith<IllegalArgumentException > { constructor (2007 , 0 , 1 ) }
237
302
assertFailsWith<IllegalArgumentException > { constructor (2007 , 13 , 1 ) }
238
303
}
304
+
305
+ private val LocalDate .next: LocalDate get() =
306
+ if (dayOfMonth != monthNumber.monthLength(isLeapYear(year))) {
307
+ LocalDate (year, monthNumber, dayOfMonth + 1 )
308
+ } else if (monthNumber != 12 ) {
309
+ LocalDate (year, monthNumber + 1 , 1 )
310
+ } else {
311
+ LocalDate (year + 1 , 1 , 1 )
312
+ }
313
+
314
+ private val LocalDate .previous: LocalDate get() =
315
+ if (dayOfMonth != 1 ) {
316
+ LocalDate (year, monthNumber, dayOfMonth - 1 )
317
+ } else if (monthNumber != 1 ) {
318
+ val newMonthNumber = monthNumber - 1
319
+ LocalDate (year, newMonthNumber, newMonthNumber.monthLength(isLeapYear(year)))
320
+ } else {
321
+ LocalDate (year - 1 , 12 , 31 )
322
+ }
0 commit comments