@@ -150,33 +150,39 @@ public actual class Instant internal constructor(public actual val epochSeconds:
150150
151151}
152152
153- private fun Instant.toZonedDateTimeFailing ( zone : TimeZone ): ZonedDateTime = try {
154- toZonedDateTime(zone )
153+ private fun Instant.toLocalDateTimeFailing ( offset : UtcOffset ): LocalDateTime = try {
154+ toLocalDateTimeImpl(offset )
155155} catch (e: IllegalArgumentException ) {
156156 throw DateTimeArithmeticException (" Can not convert instant $this to LocalDateTime to perform computations" , e)
157157}
158158
159- /* *
160- * @throws IllegalArgumentException if the [Instant] exceeds the boundaries of [LocalDateTime]
161- */
162- private fun Instant.toZonedDateTime (zone : TimeZone ): ZonedDateTime {
163- val currentOffset = zone.offsetAt(this )
164- return ZonedDateTime (toLocalDateTimeImpl(currentOffset), currentOffset)
165- }
166-
167- /* * Check that [Instant] fits in [ZonedDateTime].
159+ /* * Check that [Instant] fits in [LocalDateTime].
168160 * This is done on the results of computations for consistency with other platforms.
169161 */
170162private fun Instant.check (zone : TimeZone ): Instant = this @check.also {
171- toZonedDateTimeFailing( zone)
163+ toLocalDateTimeFailing(offsetIn( zone) )
172164}
173165
174166public actual fun Instant.plus (period : DateTimePeriod , timeZone : TimeZone ): Instant = try {
175167 with (period) {
176- val withDate = toZonedDateTimeFailing(timeZone)
177- .run { if (totalMonths != 0 ) timeZone.atZone(dateTime.plus(totalMonths, DateTimeUnit .MONTH ), offset) else this }
178- .run { if (days != 0 ) timeZone.atZone(dateTime.plus(days, DateTimeUnit .DAY ), offset) else this }
179- withDate.toInstant()
168+ 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
180186 .run { if (totalNanoseconds != 0L ) plus(0 , totalNanoseconds).check(timeZone) else this }
181187 }.check(timeZone)
182188} catch (e: ArithmeticException ) {
@@ -197,11 +203,9 @@ public actual fun Instant.plus(value: Long, unit: DateTimeUnit, timeZone: TimeZo
197203 is DateTimeUnit .DateBased -> {
198204 if (value < Int .MIN_VALUE || value > Int .MAX_VALUE )
199205 throw ArithmeticException (" Can't add a Long date-based value, as it would cause an overflow" )
200- val toZonedDateTimeFailing = toZonedDateTimeFailing(timeZone)
201- timeZone.atZone(
202- toZonedDateTimeFailing.dateTime.plus(value.toInt(), unit),
203- toZonedDateTimeFailing.offset
204- ).toInstant()
206+ val preferredOffset = offsetIn(timeZone)
207+ val initialLdt = toLocalDateTimeFailing(preferredOffset)
208+ timeZone.atZone(initialLdt.plus(value.toInt(), unit), preferredOffset).toInstant()
205209 }
206210 is DateTimeUnit .TimeBased ->
207211 check(timeZone).plus(value, unit).check(timeZone)
@@ -224,31 +228,23 @@ public actual fun Instant.plus(value: Long, unit: DateTimeUnit.TimeBased): Insta
224228 }
225229
226230public actual fun Instant.periodUntil (other : Instant , timeZone : TimeZone ): DateTimePeriod {
227- var thisLdt = toZonedDateTimeFailing(timeZone)
228- val otherLdt = other.toZonedDateTimeFailing(timeZone)
229-
230- val months =
231- thisLdt.dateTime.until(otherLdt.dateTime, DateTimeUnit .MONTH ).toLong().toInt() // `until` on dates never fails
232- thisLdt = timeZone.atZone(
233- thisLdt.dateTime.plus(months, DateTimeUnit .MONTH ),
234- thisLdt.offset
235- ) // won't throw: thisLdt + months <= otherLdt, which is known to be valid
236- val days =
237- thisLdt.dateTime.until(otherLdt.dateTime, DateTimeUnit .DAY ).toLong().toInt() // `until` on dates never fails
238- thisLdt = timeZone.atZone(
239- thisLdt.dateTime.plus(days, DateTimeUnit .DAY ),
240- thisLdt.offset
241- ) // won't throw: thisLdt + days <= otherLdt
242- val nanoseconds =
243- thisLdt.toInstant().until(otherLdt.toInstant(), DateTimeUnit .NANOSECOND ) // |otherLdt - thisLdt| < 24h
231+ val thisOffset1 = offsetIn(timeZone)
232+ val thisLdt1 = toLocalDateTimeFailing(thisOffset1)
233+ val otherLdt = other.toLocalDateTimeFailing(other.offsetIn(timeZone))
234+
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
244240
245241 return buildDateTimePeriod(months, days, nanoseconds)
246242}
247243
248244public actual fun Instant.until (other : Instant , unit : DateTimeUnit , timeZone : TimeZone ): Long =
249245 when (unit) {
250246 is DateTimeUnit .DateBased ->
251- toZonedDateTimeFailing( timeZone).dateTime. until(other.toZonedDateTimeFailing( timeZone).dateTime , unit)
247+ toLocalDateTimeFailing(offsetIn( timeZone)). until(other.toLocalDateTimeFailing(other.offsetIn( timeZone)) , unit)
252248 .toLong()
253249 is DateTimeUnit .TimeBased -> {
254250 check(timeZone); other.check(timeZone)
0 commit comments