@@ -164,33 +164,39 @@ public actual class Instant internal constructor(public actual val epochSeconds:
164164
165165}
166166
167- private fun Instant.toZonedDateTimeFailing ( zone : TimeZone ): ZonedDateTime = try {
168- toZonedDateTime(zone )
167+ private fun Instant.toLocalDateTimeFailing ( offset : UtcOffset ): LocalDateTime = try {
168+ toLocalDateTimeImpl(offset )
169169} catch (e: IllegalArgumentException ) {
170170 throw DateTimeArithmeticException (" Can not convert instant $this to LocalDateTime to perform computations" , e)
171171}
172172
173- /* *
174- * @throws IllegalArgumentException if the [Instant] exceeds the boundaries of [LocalDateTime]
175- */
176- private fun Instant.toZonedDateTime (zone : TimeZone ): ZonedDateTime {
177- val currentOffset = zone.offsetAt(this )
178- return ZonedDateTime (toLocalDateTimeImpl(currentOffset), currentOffset)
179- }
180-
181- /* * Check that [Instant] fits in [ZonedDateTime].
173+ /* * Check that [Instant] fits in [LocalDateTime].
182174 * This is done on the results of computations for consistency with other platforms.
183175 */
184176private fun Instant.check (zone : TimeZone ): Instant = this @check.also {
185- toZonedDateTimeFailing( zone)
177+ toLocalDateTimeFailing(offsetIn( zone) )
186178}
187179
188180public actual fun Instant.plus (period : DateTimePeriod , timeZone : TimeZone ): Instant = try {
189181 with (period) {
190- val withDate = toZonedDateTimeFailing(timeZone)
191- .run { if (totalMonths != 0L ) timeZone.atZone(dateTime.plus(totalMonths, DateTimeUnit .MONTH ), offset) else this }
192- .run { if (days != 0 ) timeZone.atZone(dateTime.plus(days, DateTimeUnit .DAY ), offset) else this }
193- withDate.toInstant()
182+ val initialOffset = offsetIn(timeZone)
183+ val initialLdt = toLocalDateTimeFailing(initialOffset)
184+ val offsetAfterMonths: UtcOffset
185+ val ldtAfterMonths: LocalDateTime
186+ if (totalMonths != 0L ) {
187+ val (ldt, offset) = timeZone.atZone(initialLdt.plus(totalMonths, DateTimeUnit .MONTH ), initialOffset)
188+ offsetAfterMonths = offset
189+ ldtAfterMonths = ldt
190+ } else {
191+ offsetAfterMonths = initialOffset
192+ ldtAfterMonths = initialLdt
193+ }
194+ val instantAfterMonthsAndDays = if (days != 0 ) {
195+ timeZone.atZone(ldtAfterMonths.plus(days, DateTimeUnit .DAY ), offsetAfterMonths).toInstant()
196+ } else {
197+ ldtAfterMonths.toInstant(offsetAfterMonths)
198+ }
199+ instantAfterMonthsAndDays
194200 .run { if (totalNanoseconds != 0L ) plus(0 , totalNanoseconds).check(timeZone) else this }
195201 }.check(timeZone)
196202} catch (e: ArithmeticException ) {
@@ -209,11 +215,9 @@ public actual fun Instant.minus(value: Int, unit: DateTimeUnit, timeZone: TimeZo
209215public actual fun Instant.plus (value : Long , unit : DateTimeUnit , timeZone : TimeZone ): Instant = try {
210216 when (unit) {
211217 is DateTimeUnit .DateBased -> {
212- val toZonedDateTimeFailing = toZonedDateTimeFailing(timeZone)
213- timeZone.atZone(
214- toZonedDateTimeFailing.dateTime.plus(value, unit),
215- toZonedDateTimeFailing.offset
216- ).toInstant()
218+ val preferredOffset = offsetIn(timeZone)
219+ val initialLdt = toLocalDateTimeFailing(preferredOffset)
220+ timeZone.atZone(initialLdt.plus(value, unit), preferredOffset).toInstant()
217221 }
218222 is DateTimeUnit .TimeBased ->
219223 check(timeZone).plus(value, unit).check(timeZone)
@@ -236,30 +240,23 @@ public actual fun Instant.plus(value: Long, unit: DateTimeUnit.TimeBased): Insta
236240 }
237241
238242public actual fun Instant.periodUntil (other : Instant , timeZone : TimeZone ): DateTimePeriod {
239- var thisLdt = toZonedDateTimeFailing(timeZone)
240- val otherLdt = other.toZonedDateTimeFailing(timeZone)
241-
242- val months = thisLdt.dateTime.until(otherLdt.dateTime, DateTimeUnit .MONTH ) // `until` on dates never fails
243- thisLdt = timeZone.atZone(
244- thisLdt.dateTime.plus(months, DateTimeUnit .MONTH ),
245- thisLdt.offset
246- ) // won't throw: thisLdt + months <= otherLdt, which is known to be valid
247- val days =
248- thisLdt.dateTime.until(otherLdt.dateTime, DateTimeUnit .DAY ) // `until` on dates never fails
249- thisLdt = timeZone.atZone(
250- thisLdt.dateTime.plus(days, DateTimeUnit .DAY ),
251- thisLdt.offset
252- ) // won't throw: thisLdt + days <= otherLdt
253- val nanoseconds =
254- thisLdt.toInstant().until(otherLdt.toInstant(), DateTimeUnit .NANOSECOND ) // |otherLdt - thisLdt| < 24h
243+ val thisOffset1 = offsetIn(timeZone)
244+ val thisLdt1 = toLocalDateTimeFailing(thisOffset1)
245+ val otherLdt = other.toLocalDateTimeFailing(other.offsetIn(timeZone))
246+
247+ val months = thisLdt1.until(otherLdt, DateTimeUnit .MONTH ) // `until` on dates never fails
248+ val (thisLdt2, thisOffset2) = timeZone.atZone(thisLdt1.plus(months, DateTimeUnit .MONTH ), thisOffset1) // won't throw: thisLdt + months <= otherLdt, which is known to be valid
249+ val days = thisLdt2.until(otherLdt, DateTimeUnit .DAY ) // `until` on dates never fails
250+ val (thisLdt3, thisOffset3) = timeZone.atZone(thisLdt2.plus(days, DateTimeUnit .DAY ), thisOffset2) // won't throw: thisLdt + days <= otherLdt
251+ val nanoseconds = thisLdt3.toInstant(thisOffset3).until(other, DateTimeUnit .NANOSECOND ) // |otherLdt - thisLdt| < 24h
255252
256253 return buildDateTimePeriod(months, days.toInt(), nanoseconds)
257254}
258255
259256public actual fun Instant.until (other : Instant , unit : DateTimeUnit , timeZone : TimeZone ): Long =
260257 when (unit) {
261258 is DateTimeUnit .DateBased ->
262- toZonedDateTimeFailing( timeZone).dateTime. until(other.toZonedDateTimeFailing( timeZone).dateTime , unit)
259+ toLocalDateTimeFailing(offsetIn( timeZone)). until(other.toLocalDateTimeFailing(other.offsetIn( timeZone)) , unit)
263260 .toLong()
264261 is DateTimeUnit .TimeBased -> {
265262 check(timeZone); other.check(timeZone)
0 commit comments