@@ -450,27 +450,10 @@ public fun String.toInstant(): Instant = Instant.parse(this)
450
450
public fun Instant.plus (period : DateTimePeriod , timeZone : TimeZone ): Instant = try {
451
451
with (period) {
452
452
val initialOffset = offsetIn(timeZone)
453
- val initialLdt = toLocalDateTimeFailing(initialOffset)
454
- val instantAfterMonths: Instant
455
- val offsetAfterMonths: UtcOffset
456
- val ldtAfterMonths: LocalDateTime
457
- if (totalMonths != 0L ) {
458
- val unresolvedLdtWithMonths = initialLdt.plus(totalMonths, DateTimeUnit .MONTH )
459
- instantAfterMonths = localDateTimeToInstant(unresolvedLdtWithMonths, timeZone, preferred = initialOffset)
460
- offsetAfterMonths = instantAfterMonths.offsetIn(timeZone)
461
- ldtAfterMonths = instantAfterMonths.toLocalDateTime(offsetAfterMonths)
462
- } else {
463
- instantAfterMonths = this @plus
464
- offsetAfterMonths = initialOffset
465
- ldtAfterMonths = initialLdt
466
- }
467
- val instantAfterMonthsAndDays = if (days != 0 ) {
468
- val unresolvedLdtWithDays = ldtAfterMonths.plus(days, DateTimeUnit .DAY )
469
- localDateTimeToInstant(unresolvedLdtWithDays, timeZone, preferred = offsetAfterMonths)
470
- } else {
471
- instantAfterMonths
472
- }
473
- instantAfterMonthsAndDays
453
+ val ldtPlusDate = toLocalDateTimeFailing(initialOffset)
454
+ .run { if (totalMonths != 0L ) { plus(totalMonths, DateTimeUnit .MONTH ) } else { this } }
455
+ .run { if (days != 0 ) { this .plus(days, DateTimeUnit .DAY ) } else { this } }
456
+ localDateTimeToInstant(ldtPlusDate, timeZone, preferred = initialOffset)
474
457
.run { if (totalNanoseconds != 0L ) plus(0 , totalNanoseconds).check(timeZone) else this }
475
458
}.check(timeZone)
476
459
} catch (e: ArithmeticException ) {
@@ -522,21 +505,21 @@ public fun Instant.minus(period: DateTimePeriod, timeZone: TimeZone): Instant =
522
505
public fun Instant.periodUntil (other : Instant , timeZone : TimeZone ): DateTimePeriod {
523
506
val initialOffset = offsetIn(timeZone)
524
507
val initialLdt = toLocalDateTimeFailing(initialOffset)
525
- val otherLdt = other.toLocalDateTimeFailing(other.offsetIn( timeZone) )
526
-
527
- val months = initialLdt.until (otherLdt, DateTimeUnit . MONTH ) // `until` on dates never fails
528
- val unresolvedLdtWithMonths = initialLdt.plus(months, DateTimeUnit . MONTH )
529
- // won't throw: thisLdt + months <= otherLdt, which is known to be valid
530
- val instantWithMonths = localDateTimeToInstant(unresolvedLdtWithMonths, timeZone, preferred = initialOffset)
531
- val offsetWithMonths = instantWithMonths.offsetIn(timeZone)
532
- val ldtWithMonths = instantWithMonths.toLocalDateTime(offsetWithMonths)
533
- val days = ldtWithMonths.until(otherLdt , DateTimeUnit .DAY ) // `until` on dates never fails
534
- val unresolvedLdtWithDays = ldtWithMonths.plus(days, DateTimeUnit . DAY )
508
+ val otherLdt = other.toLocalDateTimeFailing(timeZone)
509
+ val timeAfterAddingDate =
510
+ localDateTimeToInstant (otherLdt.date.atTime(initialLdt.time), timeZone, preferred = initialOffset)
511
+ val delta = when {
512
+ other > this && timeAfterAddingDate > other -> - 1 // addition won't throw: end date - date >= 1
513
+ other < this && timeAfterAddingDate < other -> 1 // addition won't throw: date - end date >= 1
514
+ else -> 0
515
+ }
516
+ val endDate = otherLdt.date.plus(delta , DateTimeUnit .DAY ) // `endDate` is guaranteed to be valid
517
+ val unresolvedLdtWithDays = endDate.atTime(initialLdt.time )
535
518
val newInstant = localDateTimeToInstant(unresolvedLdtWithDays, timeZone, preferred = initialOffset)
536
519
// won't throw: thisLdt + days <= otherLdt
537
520
val nanoseconds = newInstant.until(other, DateTimeUnit .NANOSECOND ) // |otherLdt - thisLdt| < 24h
538
-
539
- return buildDateTimePeriod(months, days.toInt() , nanoseconds)
521
+ val datePeriod = endDate - initialLdt.date
522
+ return buildDateTimePeriod(datePeriod.totalMonths, datePeriod.days , nanoseconds)
540
523
}
541
524
542
525
/* *
@@ -555,8 +538,18 @@ public fun Instant.periodUntil(other: Instant, timeZone: TimeZone): DateTimePeri
555
538
*/
556
539
public fun Instant.until (other : Instant , unit : DateTimeUnit , timeZone : TimeZone ): Long =
557
540
when (unit) {
558
- is DateTimeUnit .DateBased ->
559
- toLocalDateTimeFailing(offsetIn(timeZone)).until(other.toLocalDateTimeFailing(other.offsetIn(timeZone)), unit)
541
+ is DateTimeUnit .DateBased -> {
542
+ val start = toLocalDateTimeFailing(timeZone)
543
+ val end = other.toLocalDateTimeFailing(timeZone)
544
+ val timeAfterAddingDate =
545
+ localDateTimeToInstant(end.date.atTime(start.time), timeZone, preferred = this .offsetIn(timeZone))
546
+ val delta = when {
547
+ other > this && timeAfterAddingDate > other -> - 1 // addition won't throw: end date - date >= 1
548
+ other < this && timeAfterAddingDate < other -> 1 // addition won't throw: date - end date >= 1
549
+ else -> 0
550
+ }
551
+ start.date.until(end.date.plus(delta, DateTimeUnit .DAY ), unit)
552
+ }
560
553
is DateTimeUnit .TimeBased -> {
561
554
check(timeZone); other.check(timeZone)
562
555
until(other, unit)
@@ -890,11 +883,14 @@ private fun Instant.toLocalDateTimeFailing(offset: UtcOffset): LocalDateTime = t
890
883
throw DateTimeArithmeticException (" Can not convert instant $this to LocalDateTime to perform computations" , e)
891
884
}
892
885
886
+ private fun Instant.toLocalDateTimeFailing (timeZone : TimeZone ): LocalDateTime =
887
+ toLocalDateTimeFailing(offsetIn(timeZone))
888
+
893
889
/* * Check that [Instant] fits in [LocalDateTime].
894
890
* This is done on the results of computations for consistency with other platforms.
895
891
*/
896
892
private fun Instant.check (zone : TimeZone ): Instant = this @check.also {
897
- toLocalDateTimeFailing(offsetIn( zone) )
893
+ toLocalDateTimeFailing(zone)
898
894
}
899
895
900
896
private fun LocalDateTime.plus (value : Long , unit : DateTimeUnit .DateBased ) =
@@ -908,18 +904,3 @@ private fun LocalDateTime.plus(value: Int, unit: DateTimeUnit.DateBased) =
908
904
* @throws IllegalArgumentException if the boundaries of Instant are overflown
909
905
*/
910
906
internal expect fun Instant.plus (secondsToAdd : Long , nanosToAdd : Long ): Instant
911
-
912
- // org.threeten.bp.LocalDateTime#until
913
- internal fun LocalDateTime.until (other : LocalDateTime , unit : DateTimeUnit .DateBased ): Long {
914
- val otherDate = other.date
915
- val delta = when {
916
- otherDate > date && other.time < time -> - 1 // addition won't throw: endDate - date >= 1
917
- otherDate < date && other.time > time -> 1 // addition won't throw: date - endDate >= 1
918
- else -> 0
919
- }
920
- val endDate = otherDate.plus(delta, DateTimeUnit .DAY )
921
- return when (unit) {
922
- is DateTimeUnit .MonthBased -> date.until(endDate, DateTimeUnit .MONTH ) / unit.months
923
- is DateTimeUnit .DayBased -> date.until(endDate, DateTimeUnit .DAY ) / unit.days
924
- }
925
- }
0 commit comments