Skip to content

Commit 38d579e

Browse files
committed
Don't resolve LocalDateTime between calendar operations
See #330
1 parent 6a16657 commit 38d579e

File tree

1 file changed

+14
-27
lines changed

1 file changed

+14
-27
lines changed

core/native/src/Instant.kt

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -268,23 +268,10 @@ private fun Instant.check(zone: TimeZone): Instant = [email protected] {
268268
public actual fun Instant.plus(period: DateTimePeriod, timeZone: TimeZone): Instant = try {
269269
with(period) {
270270
val initialOffset = offsetIn(timeZone)
271-
val initialLdt = toLocalDateTimeFailing(initialOffset)
272-
val offsetAfterMonths: UtcOffset
273-
val ldtAfterMonths: LocalDateTime
274-
if (totalMonths != 0) {
275-
val (ldt, offset) = timeZone.atZone(initialLdt.plus(totalMonths, DateTimeUnit.MONTH), initialOffset)
276-
offsetAfterMonths = offset
277-
ldtAfterMonths = ldt
278-
} else {
279-
offsetAfterMonths = initialOffset
280-
ldtAfterMonths = initialLdt
281-
}
282-
val instantAfterMonthsAndDays = if (days != 0) {
283-
timeZone.atZone(ldtAfterMonths.plus(days, DateTimeUnit.DAY), offsetAfterMonths).toInstant()
284-
} else {
285-
ldtAfterMonths.toInstant(offsetAfterMonths)
286-
}
287-
instantAfterMonthsAndDays
271+
val newLdt = toLocalDateTimeFailing(initialOffset)
272+
.run { if (totalMonths != 0) { plus(totalMonths, DateTimeUnit.MONTH) } else { this } }
273+
.run { if (days != 0) { plus(days, DateTimeUnit.DAY) } else { this } }
274+
timeZone.atZone(newLdt, preferred = initialOffset).toInstant()
288275
.run { if (totalNanoseconds != 0L) plus(0, totalNanoseconds).check(timeZone) else this }
289276
}.check(timeZone)
290277
} catch (e: ArithmeticException) {
@@ -305,9 +292,9 @@ public actual fun Instant.plus(value: Long, unit: DateTimeUnit, timeZone: TimeZo
305292
is DateTimeUnit.DateBased -> {
306293
if (value < Int.MIN_VALUE || value > Int.MAX_VALUE)
307294
throw ArithmeticException("Can't add a Long date-based value, as it would cause an overflow")
308-
val preferredOffset = offsetIn(timeZone)
309-
val initialLdt = toLocalDateTimeFailing(preferredOffset)
310-
timeZone.atZone(initialLdt.plus(value.toInt(), unit), preferredOffset).toInstant()
295+
val initialOffset = offsetIn(timeZone)
296+
val initialLdt = toLocalDateTimeFailing(initialOffset)
297+
timeZone.atZone(initialLdt.plus(value.toInt(), unit), preferred = initialOffset).toInstant()
311298
}
312299
is DateTimeUnit.TimeBased ->
313300
check(timeZone).plus(value, unit).check(timeZone)
@@ -330,15 +317,15 @@ public actual fun Instant.plus(value: Long, unit: DateTimeUnit.TimeBased): Insta
330317
}
331318

332319
public actual fun Instant.periodUntil(other: Instant, timeZone: TimeZone): DateTimePeriod {
333-
val thisOffset1 = offsetIn(timeZone)
334-
val thisLdt1 = toLocalDateTimeFailing(thisOffset1)
320+
val initialOffset = offsetIn(timeZone)
321+
val initialLdt = toLocalDateTimeFailing(initialOffset)
335322
val otherLdt = other.toLocalDateTimeFailing(other.offsetIn(timeZone))
336323

337-
val months = thisLdt1.until(otherLdt, DateTimeUnit.MONTH).toLong().toInt() // `until` on dates never fails
338-
val (thisLdt2, thisOffset2) = timeZone.atZone(thisLdt1.plus(months, DateTimeUnit.MONTH), thisOffset1) // won't throw: thisLdt + months <= otherLdt, which is known to be valid
339-
val days = thisLdt2.until(otherLdt, DateTimeUnit.DAY).toLong().toInt() // `until` on dates never fails
340-
val (thisLdt3, thisOffset3) = timeZone.atZone(thisLdt2.plus(days, DateTimeUnit.DAY), thisOffset2) // won't throw: thisLdt + days <= otherLdt
341-
val nanoseconds = thisLdt3.toInstant(thisOffset3).until(other, DateTimeUnit.NANOSECOND) // |otherLdt - thisLdt| < 24h
324+
val months = initialLdt.until(otherLdt, DateTimeUnit.MONTH).toLong().toInt() // `until` on dates never fails
325+
val ldtWithMonths = initialLdt.plus(months, DateTimeUnit.MONTH) // won't throw: thisLdt + months <= otherLdt, which is known to be valid
326+
val days = ldtWithMonths.until(otherLdt, DateTimeUnit.DAY).toLong().toInt() // `until` on dates never fails
327+
val newInstant = timeZone.atZone(ldtWithMonths.plus(days, DateTimeUnit.DAY), preferred = initialOffset).toInstant() // won't throw: thisLdt + days <= otherLdt
328+
val nanoseconds = newInstant.until(other, DateTimeUnit.NANOSECOND) // |otherLdt - thisLdt| < 24h
342329

343330
return buildDateTimePeriod(months, days, nanoseconds)
344331
}

0 commit comments

Comments
 (0)