@@ -252,33 +252,39 @@ public actual class Instant internal constructor(public actual val epochSeconds:
252
252
253
253
}
254
254
255
- private fun Instant.toZonedDateTimeFailing ( zone : TimeZone ): ZonedDateTime = try {
256
- toZonedDateTime(zone )
255
+ private fun Instant.toLocalDateTimeFailing ( offset : UtcOffset ): LocalDateTime = try {
256
+ toLocalDateTimeImpl(offset )
257
257
} catch (e: IllegalArgumentException ) {
258
258
throw DateTimeArithmeticException (" Can not convert instant $this to LocalDateTime to perform computations" , e)
259
259
}
260
260
261
- /* *
262
- * @throws IllegalArgumentException if the [Instant] exceeds the boundaries of [LocalDateTime]
263
- */
264
- private fun Instant.toZonedDateTime (zone : TimeZone ): ZonedDateTime {
265
- val currentOffset = zone.offsetAt(this )
266
- return ZonedDateTime (toLocalDateTimeImpl(currentOffset), currentOffset)
267
- }
268
-
269
- /* * Check that [Instant] fits in [ZonedDateTime].
261
+ /* * Check that [Instant] fits in [LocalDateTime].
270
262
* This is done on the results of computations for consistency with other platforms.
271
263
*/
272
264
private fun Instant.check (zone : TimeZone ): Instant = this @check.also {
273
- toZonedDateTimeFailing( zone)
265
+ toLocalDateTimeFailing(offsetIn( zone) )
274
266
}
275
267
276
268
public actual fun Instant.plus (period : DateTimePeriod , timeZone : TimeZone ): Instant = try {
277
269
with (period) {
278
- val withDate = toZonedDateTimeFailing(timeZone)
279
- .run { if (totalMonths != 0 ) timeZone.atZone(dateTime.plus(totalMonths, DateTimeUnit .MONTH ), offset) else this }
280
- .run { if (days != 0 ) timeZone.atZone(dateTime.plus(days, DateTimeUnit .DAY ), offset) else this }
281
- withDate.toInstant()
270
+ 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
282
288
.run { if (totalNanoseconds != 0L ) plus(0 , totalNanoseconds).check(timeZone) else this }
283
289
}.check(timeZone)
284
290
} catch (e: ArithmeticException ) {
@@ -299,11 +305,9 @@ public actual fun Instant.plus(value: Long, unit: DateTimeUnit, timeZone: TimeZo
299
305
is DateTimeUnit .DateBased -> {
300
306
if (value < Int .MIN_VALUE || value > Int .MAX_VALUE )
301
307
throw ArithmeticException (" Can't add a Long date-based value, as it would cause an overflow" )
302
- val toZonedDateTimeFailing = toZonedDateTimeFailing(timeZone)
303
- timeZone.atZone(
304
- toZonedDateTimeFailing.dateTime.plus(value.toInt(), unit),
305
- toZonedDateTimeFailing.offset
306
- ).toInstant()
308
+ val preferredOffset = offsetIn(timeZone)
309
+ val initialLdt = toLocalDateTimeFailing(preferredOffset)
310
+ timeZone.atZone(initialLdt.plus(value.toInt(), unit), preferredOffset).toInstant()
307
311
}
308
312
is DateTimeUnit .TimeBased ->
309
313
check(timeZone).plus(value, unit).check(timeZone)
@@ -326,31 +330,23 @@ public actual fun Instant.plus(value: Long, unit: DateTimeUnit.TimeBased): Insta
326
330
}
327
331
328
332
public actual fun Instant.periodUntil (other : Instant , timeZone : TimeZone ): DateTimePeriod {
329
- var thisLdt = toZonedDateTimeFailing(timeZone)
330
- val otherLdt = other.toZonedDateTimeFailing(timeZone)
331
-
332
- val months =
333
- thisLdt.dateTime.until(otherLdt.dateTime, DateTimeUnit .MONTH ).toLong().toInt() // `until` on dates never fails
334
- thisLdt = timeZone.atZone(
335
- thisLdt.dateTime.plus(months, DateTimeUnit .MONTH ),
336
- thisLdt.offset
337
- ) // won't throw: thisLdt + months <= otherLdt, which is known to be valid
338
- val days =
339
- thisLdt.dateTime.until(otherLdt.dateTime, DateTimeUnit .DAY ).toLong().toInt() // `until` on dates never fails
340
- thisLdt = timeZone.atZone(
341
- thisLdt.dateTime.plus(days, DateTimeUnit .DAY ),
342
- thisLdt.offset
343
- ) // won't throw: thisLdt + days <= otherLdt
344
- val nanoseconds =
345
- thisLdt.toInstant().until(otherLdt.toInstant(), DateTimeUnit .NANOSECOND ) // |otherLdt - thisLdt| < 24h
333
+ val thisOffset1 = offsetIn(timeZone)
334
+ val thisLdt1 = toLocalDateTimeFailing(thisOffset1)
335
+ val otherLdt = other.toLocalDateTimeFailing(other.offsetIn(timeZone))
336
+
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
346
342
347
343
return buildDateTimePeriod(months, days, nanoseconds)
348
344
}
349
345
350
346
public actual fun Instant.until (other : Instant , unit : DateTimeUnit , timeZone : TimeZone ): Long =
351
347
when (unit) {
352
348
is DateTimeUnit .DateBased ->
353
- toZonedDateTimeFailing( timeZone).dateTime. until(other.toZonedDateTimeFailing( timeZone).dateTime , unit)
349
+ toLocalDateTimeFailing(offsetIn( timeZone)). until(other.toLocalDateTimeFailing(other.offsetIn( timeZone)) , unit)
354
350
.toLong()
355
351
is DateTimeUnit .TimeBased -> {
356
352
check(timeZone); other.check(timeZone)
0 commit comments