@@ -57,7 +57,7 @@ class InstantTest {
57
57
* Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos
58
58
*/
59
59
@Test
60
- fun instantParsing () {
60
+ fun parseIsoString () {
61
61
val instants = arrayOf(
62
62
Triple (" 1970-01-01T00:00:00Z" , 0 , 0 ),
63
63
Triple (" 1970-01-01t00:00:00Z" , 0 , 0 ),
@@ -78,8 +78,12 @@ class InstantTest {
78
78
val instant = Instant .parse(str)
79
79
assertEquals(seconds.toLong() * 1000 + nanos / 1000000 , instant.toEpochMilliseconds())
80
80
}
81
- }
82
81
82
+ assertInvalidFormat { Instant .parse(" x" ) }
83
+ assertInvalidFormat { Instant .parse(" 12020-12-31T23:59:59.000000000Z" ) }
84
+ // this string represents an Instant that is currently larger than Instant.MAX any of the implementations:
85
+ assertInvalidFormat { Instant .parse(" +1000000001-12-31T23:59:59.000000000Z" ) }
86
+ }
83
87
84
88
@OptIn(ExperimentalTime ::class )
85
89
@Test
@@ -296,29 +300,29 @@ class InstantTest {
296
300
assertEquals(" +19999-12-31T23:59:59.000000009Z" , LocalDateTime (19999 , 12 , 31 , 23 , 59 , 59 , 9 ).toInstant(TimeZone .UTC ).toString())
297
301
}
298
302
303
+ }
304
+
305
+ @OptIn(ExperimentalTime ::class )
306
+ class InstantRangeTest {
307
+ private val UTC = TimeZone .UTC
308
+ private val maxValidInstant = LocalDateTime .MAX .toInstant(UTC )
309
+ private val minValidInstant = LocalDateTime .MIN .toInstant(UTC )
310
+
299
311
private val largePositiveLongs = listOf (Long .MAX_VALUE , Long .MAX_VALUE - 1 , Long .MAX_VALUE - 50 )
300
312
private val largeNegativeLongs = listOf (Long .MIN_VALUE , Long .MIN_VALUE + 1 , Long .MIN_VALUE + 50 )
301
- @OptIn( ExperimentalTime :: class )
313
+
302
314
private val largePositiveInstants = listOf (Instant .MAX , Instant .MAX - 1 .seconds, Instant .MAX - 50 .seconds)
303
- @OptIn(ExperimentalTime ::class )
304
315
private val largeNegativeInstants = listOf (Instant .MIN , Instant .MIN + 1 .seconds, Instant .MIN + 50 .seconds)
316
+
305
317
private val smallInstants = listOf (
306
318
Instant .fromEpochMilliseconds(0 ),
307
319
Instant .fromEpochMilliseconds(1003 ),
308
320
Instant .fromEpochMilliseconds(253112 )
309
321
)
310
322
311
- @Test
312
- fun testParsingThrowing () {
313
- assertFailsWith<DateTimeFormatException > { Instant .parse(" x" ) }
314
- assertFailsWith<DateTimeFormatException > { Instant .parse(" 12020-12-31T23:59:59.000000000Z" ) }
315
- // this string represents an Instant that is currently larger than Instant.MAX any of the implementations:
316
- assertFailsWith<DateTimeFormatException > { Instant .parse(" +1000000001-12-31T23:59:59.000000000Z" ) }
317
- }
318
323
319
- @ExperimentalTime
320
324
@Test
321
- fun testConstructorAccessorClamping () {
325
+ fun epochMillisecondsClamping () {
322
326
// toEpochMilliseconds()/fromEpochMilliseconds()
323
327
// assuming that ranges of Long (representing a number of milliseconds) and Instant are not just overlapping,
324
328
// but one is included in the other.
@@ -332,7 +336,7 @@ class InstantTest {
332
336
}
333
337
for (milliseconds in largePositiveLongs + largeNegativeLongs) {
334
338
assertEquals(milliseconds, Instant .fromEpochMilliseconds(milliseconds).toEpochMilliseconds(),
335
- " $milliseconds " )
339
+ " $milliseconds " )
336
340
}
337
341
} else {
338
342
/* Any Instant is representable as a number of milliseconds in Long */
@@ -344,9 +348,13 @@ class InstantTest {
344
348
}
345
349
for (instant in largePositiveInstants + smallInstants + largeNegativeInstants) {
346
350
assertEquals(instant.epochSeconds,
347
- Instant .fromEpochMilliseconds(instant.toEpochMilliseconds()).epochSeconds, " $instant " )
351
+ Instant .fromEpochMilliseconds(instant.toEpochMilliseconds()).epochSeconds, " $instant " )
348
352
}
349
353
}
354
+ }
355
+
356
+ @Test
357
+ fun epochSecondsClamping () {
350
358
// fromEpochSeconds
351
359
// On all platforms Long.MAX_VALUE of seconds is not a valid instant.
352
360
for (seconds in largePositiveLongs) {
@@ -360,121 +368,106 @@ class InstantTest {
360
368
}
361
369
}
362
370
363
- @OptIn(ExperimentalTime ::class )
364
371
@Test
365
- fun testArithmeticClamping () {
366
- for (instant in smallInstants + largeNegativeInstants + largePositiveInstants) {
367
- assertEquals(Instant .MAX , instant + Duration .INFINITE )
368
- }
369
- for (instant in smallInstants + largeNegativeInstants + largePositiveInstants) {
370
- assertEquals(Instant .MIN , instant - Duration .INFINITE )
372
+ fun durationArithmeticClamping () {
373
+ val longDurations = listOf (Duration .INFINITE , Double .MAX_VALUE .nanoseconds, Long .MAX_VALUE .seconds)
374
+
375
+ for (duration in longDurations) {
376
+ for (instant in smallInstants + largeNegativeInstants + largePositiveInstants) {
377
+ assertEquals(Instant .MAX , instant + duration)
378
+ }
379
+ for (instant in smallInstants + largeNegativeInstants + largePositiveInstants) {
380
+ assertEquals(Instant .MIN , instant - duration)
381
+ }
371
382
}
372
383
assertEquals(Instant .MAX , (Instant .MAX - 4 .seconds) + 5 .seconds)
373
384
assertEquals(Instant .MIN , (Instant .MIN + 10 .seconds) - 12 .seconds)
374
385
}
375
386
376
- @OptIn(ExperimentalTime ::class )
377
387
@Test
378
- fun testCalendarArithmeticThrowing () {
379
- val maxValidInstant = LocalDateTime .MAX .toInstant(TimeZone .UTC )
380
- val minValidInstant = LocalDateTime .MIN .toInstant(TimeZone .UTC )
381
-
388
+ fun periodArithmeticOutOfRange () {
382
389
// Instant.plus(DateTimePeriod(), TimeZone)
383
390
// Arithmetic overflow
384
391
for (instant in smallInstants + largeNegativeInstants + largePositiveInstants) {
385
- assertFailsWith<DateTimeArithmeticException >(" $instant " ) {
386
- instant.plus(DateTimePeriod (seconds = Long .MAX_VALUE ), TimeZone .UTC )
387
- }
388
- assertFailsWith<DateTimeArithmeticException >(" $instant " ) {
389
- instant.plus(DateTimePeriod (seconds = Long .MIN_VALUE ), TimeZone .UTC )
390
- }
392
+ assertArithmeticFails(" $instant " ) { instant.plus(DateTimePeriod (seconds = Long .MAX_VALUE ), UTC ) }
393
+ assertArithmeticFails(" $instant " ) { instant.plus(DateTimePeriod (seconds = Long .MIN_VALUE ), UTC ) }
391
394
}
392
395
// Overflowing a LocalDateTime in input
393
- maxValidInstant.plus(DateTimePeriod (nanoseconds = - 1 ), TimeZone .UTC )
394
- minValidInstant.plus(DateTimePeriod (nanoseconds = 1 ), TimeZone .UTC )
395
- assertFailsWith<DateTimeArithmeticException > {
396
- (maxValidInstant + 1 .nanoseconds).plus(DateTimePeriod (nanoseconds = - 2 ), TimeZone .UTC )
397
- }
398
- assertFailsWith<DateTimeArithmeticException > {
399
- (minValidInstant - 1 .nanoseconds).plus(DateTimePeriod (nanoseconds = 2 ), TimeZone .UTC )
400
- }
396
+ maxValidInstant.plus(DateTimePeriod (nanoseconds = - 1 ), UTC )
397
+ minValidInstant.plus(DateTimePeriod (nanoseconds = 1 ), UTC )
398
+ assertArithmeticFails { (maxValidInstant + 1 .nanoseconds).plus(DateTimePeriod (nanoseconds = - 2 ), UTC ) }
399
+ assertArithmeticFails { (minValidInstant - 1 .nanoseconds).plus(DateTimePeriod (nanoseconds = 2 ), UTC ) }
401
400
// Overflowing a LocalDateTime in result
402
- assertFailsWith<DateTimeArithmeticException > {
403
- maxValidInstant.plus(DateTimePeriod (nanoseconds = 1 ), TimeZone .UTC )
404
- }
405
- assertFailsWith<DateTimeArithmeticException > {
406
- minValidInstant.plus(DateTimePeriod (nanoseconds = - 1 ), TimeZone .UTC )
407
- }
401
+ assertArithmeticFails { maxValidInstant.plus(DateTimePeriod (nanoseconds = 1 ), UTC ) }
402
+ assertArithmeticFails { minValidInstant.plus(DateTimePeriod (nanoseconds = - 1 ), UTC ) }
408
403
// Overflowing a LocalDateTime in intermediate computations
409
- assertFailsWith<DateTimeArithmeticException > {
410
- maxValidInstant.plus(DateTimePeriod (seconds = 1 , nanoseconds = - 1_000_000_001 ), TimeZone .UTC )
411
- }
412
- assertFailsWith<DateTimeArithmeticException > {
413
- maxValidInstant.plus(DateTimePeriod (hours = 1 , minutes = - 61 ), TimeZone .UTC )
414
- }
415
- assertFailsWith<DateTimeArithmeticException > {
416
- maxValidInstant.plus(DateTimePeriod (days = 1 , hours = - 48 ), TimeZone .UTC )
417
- }
404
+ assertArithmeticFails { maxValidInstant.plus(DateTimePeriod (seconds = 1 , nanoseconds = - 1_000_000_001 ), UTC ) }
405
+ assertArithmeticFails { maxValidInstant.plus(DateTimePeriod (hours = 1 , minutes = - 61 ), UTC ) }
406
+ assertArithmeticFails { maxValidInstant.plus(DateTimePeriod (days = 1 , hours = - 48 ), UTC ) }
407
+ }
418
408
409
+ @Test
410
+ fun unitArithmeticOutOfRange () {
419
411
// Instant.plus(Long, DateTimeUnit, TimeZone)
420
412
// Arithmetic overflow
421
413
for (instant in smallInstants + largeNegativeInstants + largePositiveInstants) {
422
- assertFailsWith<DateTimeArithmeticException >(" $instant " ) {
423
- instant.plus(Long .MAX_VALUE , DateTimeUnit .SECOND , TimeZone .UTC )
424
- }
425
- assertFailsWith<DateTimeArithmeticException >(" $instant " ) {
426
- instant.plus(Long .MIN_VALUE , DateTimeUnit .SECOND , TimeZone .UTC )
427
- }
428
- assertFailsWith<DateTimeArithmeticException >(" $instant " ) {
429
- instant.plus(Long .MAX_VALUE , DateTimeUnit .YEAR , TimeZone .UTC )
430
- }
431
- assertFailsWith<DateTimeArithmeticException >(" $instant " ) {
432
- instant.plus(Long .MIN_VALUE , DateTimeUnit .YEAR , TimeZone .UTC )
433
- }
414
+ assertArithmeticFails(" $instant " ) { instant.plus(Long .MAX_VALUE , DateTimeUnit .SECOND , UTC ) }
415
+ assertArithmeticFails(" $instant " ) { instant.plus(Long .MIN_VALUE , DateTimeUnit .SECOND , UTC ) }
416
+ assertArithmeticFails(" $instant " ) { instant.plus(Long .MAX_VALUE , DateTimeUnit .YEAR , UTC ) }
417
+ assertArithmeticFails(" $instant " ) { instant.plus(Long .MIN_VALUE , DateTimeUnit .YEAR , UTC ) }
434
418
}
435
419
// Overflowing a LocalDateTime in input
436
- maxValidInstant.plus(- 1 , DateTimeUnit .NANOSECOND , TimeZone .UTC )
437
- minValidInstant.plus(1 , DateTimeUnit .NANOSECOND , TimeZone .UTC )
438
- assertFailsWith<DateTimeArithmeticException > {
439
- (maxValidInstant + 1 .nanoseconds).plus(- 2 , DateTimeUnit .NANOSECOND , TimeZone .UTC )
440
- }
441
- assertFailsWith<DateTimeArithmeticException > {
442
- (minValidInstant - 1 .nanoseconds).plus(2 , DateTimeUnit .NANOSECOND , TimeZone .UTC )
443
- }
420
+ maxValidInstant.plus(- 1 , DateTimeUnit .NANOSECOND , UTC )
421
+ minValidInstant.plus(1 , DateTimeUnit .NANOSECOND , UTC )
422
+ assertArithmeticFails { (maxValidInstant + 1 .nanoseconds).plus(- 2 , DateTimeUnit .NANOSECOND , UTC ) }
423
+ assertArithmeticFails { (minValidInstant - 1 .nanoseconds).plus(2 , DateTimeUnit .NANOSECOND , UTC ) }
444
424
// Overflowing a LocalDateTime in result
445
- assertFailsWith<DateTimeArithmeticException > {
446
- maxValidInstant.plus(1 , DateTimeUnit .NANOSECOND , TimeZone .UTC )
447
- }
448
- assertFailsWith<DateTimeArithmeticException > {
449
- maxValidInstant.plus(1 , DateTimeUnit .YEAR , TimeZone .UTC )
450
- }
451
- assertFailsWith<DateTimeArithmeticException > {
452
- minValidInstant.plus(- 1 , DateTimeUnit .NANOSECOND , TimeZone .UTC )
453
- }
454
- assertFailsWith<DateTimeArithmeticException > {
455
- minValidInstant.plus(- 1 , DateTimeUnit .YEAR , TimeZone .UTC )
456
- }
425
+ assertArithmeticFails { maxValidInstant.plus(1 , DateTimeUnit .NANOSECOND , UTC ) }
426
+ assertArithmeticFails { maxValidInstant.plus(1 , DateTimeUnit .YEAR , UTC ) }
427
+ assertArithmeticFails { minValidInstant.plus(- 1 , DateTimeUnit .NANOSECOND , UTC ) }
428
+ assertArithmeticFails { minValidInstant.plus(- 1 , DateTimeUnit .YEAR , UTC ) }
429
+ }
457
430
431
+ @Test
432
+ fun periodUntilOutOfRange () {
458
433
// Instant.periodUntil
459
- maxValidInstant.periodUntil(minValidInstant, TimeZone .UTC )
460
- assertFailsWith<DateTimeArithmeticException > {
461
- (maxValidInstant + 1 .nanoseconds).periodUntil(minValidInstant, TimeZone .UTC )
462
- }
463
- assertFailsWith<DateTimeArithmeticException > {
464
- maxValidInstant.periodUntil(minValidInstant - 1 .nanoseconds, TimeZone .UTC )
465
- }
434
+ maxValidInstant.periodUntil(minValidInstant, UTC )
435
+ assertArithmeticFails { (maxValidInstant + 1 .nanoseconds).periodUntil(minValidInstant, UTC ) }
436
+ assertArithmeticFails { maxValidInstant.periodUntil(minValidInstant - 1 .nanoseconds, UTC ) }
437
+ }
438
+
439
+ @Test
440
+ fun unitsUntilClamping () {
441
+ // Arithmetic overflow of the resulting number
442
+ assertEquals(Long .MAX_VALUE , minValidInstant.until(maxValidInstant, DateTimeUnit .NANOSECOND , UTC ))
443
+ assertEquals(Long .MIN_VALUE , maxValidInstant.until(minValidInstant, DateTimeUnit .NANOSECOND , UTC ))
444
+ }
466
445
446
+ @Test
447
+ fun unitsUntilOutOfRange () {
467
448
// Instant.until
468
- // Arithmetic overflow
469
- assertEquals(Long .MAX_VALUE , minValidInstant.until(maxValidInstant, DateTimeUnit .NANOSECOND , TimeZone .UTC ))
470
- assertEquals(Long .MIN_VALUE , maxValidInstant.until(minValidInstant, DateTimeUnit .NANOSECOND , TimeZone .UTC ))
471
449
// Overflowing a LocalDateTime in input
472
- assertFailsWith<DateTimeArithmeticException > {
473
- (maxValidInstant + 1 .nanoseconds).until(maxValidInstant, DateTimeUnit .NANOSECOND , TimeZone .UTC )
474
- }
475
- assertFailsWith<DateTimeArithmeticException > {
476
- maxValidInstant.until(maxValidInstant + 1 .nanoseconds, DateTimeUnit .NANOSECOND , TimeZone .UTC )
477
- }
450
+ assertArithmeticFails { (maxValidInstant + 1 .nanoseconds).until(maxValidInstant, DateTimeUnit .NANOSECOND , UTC ) }
451
+ assertArithmeticFails { maxValidInstant.until(maxValidInstant + 1 .nanoseconds, DateTimeUnit .NANOSECOND , UTC ) }
452
+ }
453
+ }
454
+
455
+
456
+ @Suppress(" INVISIBLE_REFERENCE" , " INVISIBLE_MEMBER" )
457
+ @kotlin.internal.InlineOnly
458
+ inline fun <T > assertArithmeticFails (message : String? = null, f : () -> T ) {
459
+ assertFailsWith<DateTimeArithmeticException >(message) {
460
+ val result = f()
461
+ fail(result.toString())
478
462
}
463
+ }
479
464
465
+ @Suppress(" INVISIBLE_REFERENCE" , " INVISIBLE_MEMBER" )
466
+ @kotlin.internal.InlineOnly
467
+ inline fun <T > assertInvalidFormat (message : String? = null, f : () -> T ) {
468
+ assertFailsWith<DateTimeFormatException >(message) {
469
+ val result = f()
470
+ fail(result.toString())
471
+ }
480
472
}
473
+
0 commit comments