Skip to content

Commit d6a5fa3

Browse files
committed
Don't resolve LocalDateTime between calendar operations
See #330
1 parent f5aa7d4 commit d6a5fa3

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
@@ -166,23 +166,10 @@ private fun Instant.check(zone: TimeZone): Instant = [email protected] {
166166
public actual fun Instant.plus(period: DateTimePeriod, timeZone: TimeZone): Instant = try {
167167
with(period) {
168168
val initialOffset = offsetIn(timeZone)
169-
val initialLdt = toLocalDateTimeFailing(initialOffset)
170-
val offsetAfterMonths: UtcOffset
171-
val ldtAfterMonths: LocalDateTime
172-
if (totalMonths != 0) {
173-
val (ldt, offset) = timeZone.atZone(initialLdt.plus(totalMonths, DateTimeUnit.MONTH), initialOffset)
174-
offsetAfterMonths = offset
175-
ldtAfterMonths = ldt
176-
} else {
177-
offsetAfterMonths = initialOffset
178-
ldtAfterMonths = initialLdt
179-
}
180-
val instantAfterMonthsAndDays = if (days != 0) {
181-
timeZone.atZone(ldtAfterMonths.plus(days, DateTimeUnit.DAY), offsetAfterMonths).toInstant()
182-
} else {
183-
ldtAfterMonths.toInstant(offsetAfterMonths)
184-
}
185-
instantAfterMonthsAndDays
169+
val newLdt = toLocalDateTimeFailing(initialOffset)
170+
.run { if (totalMonths != 0) { plus(totalMonths, DateTimeUnit.MONTH) } else { this } }
171+
.run { if (days != 0) { plus(days, DateTimeUnit.DAY) } else { this } }
172+
timeZone.atZone(newLdt, preferred = initialOffset).toInstant()
186173
.run { if (totalNanoseconds != 0L) plus(0, totalNanoseconds).check(timeZone) else this }
187174
}.check(timeZone)
188175
} catch (e: ArithmeticException) {
@@ -203,9 +190,9 @@ public actual fun Instant.plus(value: Long, unit: DateTimeUnit, timeZone: TimeZo
203190
is DateTimeUnit.DateBased -> {
204191
if (value < Int.MIN_VALUE || value > Int.MAX_VALUE)
205192
throw ArithmeticException("Can't add a Long date-based value, as it would cause an overflow")
206-
val preferredOffset = offsetIn(timeZone)
207-
val initialLdt = toLocalDateTimeFailing(preferredOffset)
208-
timeZone.atZone(initialLdt.plus(value.toInt(), unit), preferredOffset).toInstant()
193+
val initialOffset = offsetIn(timeZone)
194+
val initialLdt = toLocalDateTimeFailing(initialOffset)
195+
timeZone.atZone(initialLdt.plus(value.toInt(), unit), preferred = initialOffset).toInstant()
209196
}
210197
is DateTimeUnit.TimeBased ->
211198
check(timeZone).plus(value, unit).check(timeZone)
@@ -228,15 +215,15 @@ public actual fun Instant.plus(value: Long, unit: DateTimeUnit.TimeBased): Insta
228215
}
229216

230217
public actual fun Instant.periodUntil(other: Instant, timeZone: TimeZone): DateTimePeriod {
231-
val thisOffset1 = offsetIn(timeZone)
232-
val thisLdt1 = toLocalDateTimeFailing(thisOffset1)
218+
val initialOffset = offsetIn(timeZone)
219+
val initialLdt = toLocalDateTimeFailing(initialOffset)
233220
val otherLdt = other.toLocalDateTimeFailing(other.offsetIn(timeZone))
234221

235-
val months = thisLdt1.until(otherLdt, DateTimeUnit.MONTH).toLong().toInt() // `until` on dates never fails
236-
val (thisLdt2, thisOffset2) = timeZone.atZone(thisLdt1.plus(months, DateTimeUnit.MONTH), thisOffset1) // won't throw: thisLdt + months <= otherLdt, which is known to be valid
237-
val days = thisLdt2.until(otherLdt, DateTimeUnit.DAY).toLong().toInt() // `until` on dates never fails
238-
val (thisLdt3, thisOffset3) = timeZone.atZone(thisLdt2.plus(days, DateTimeUnit.DAY), thisOffset2) // won't throw: thisLdt + days <= otherLdt
239-
val nanoseconds = thisLdt3.toInstant(thisOffset3).until(other, DateTimeUnit.NANOSECOND) // |otherLdt - thisLdt| < 24h
222+
val months = initialLdt.until(otherLdt, DateTimeUnit.MONTH).toLong().toInt() // `until` on dates never fails
223+
val ldtWithMonths = initialLdt.plus(months, DateTimeUnit.MONTH) // won't throw: thisLdt + months <= otherLdt, which is known to be valid
224+
val days = ldtWithMonths.until(otherLdt, DateTimeUnit.DAY).toLong().toInt() // `until` on dates never fails
225+
val newInstant = timeZone.atZone(ldtWithMonths.plus(days, DateTimeUnit.DAY), preferred = initialOffset).toInstant() // won't throw: thisLdt + days <= otherLdt
226+
val nanoseconds = newInstant.until(other, DateTimeUnit.NANOSECOND) // |otherLdt - thisLdt| < 24h
240227

241228
return buildDateTimePeriod(months, days, nanoseconds)
242229
}

0 commit comments

Comments
 (0)