@@ -150,33 +150,39 @@ public actual class Instant internal constructor(public actual val epochSeconds:
150
150
151
151
}
152
152
153
- private fun Instant.toZonedDateTimeFailing ( zone : TimeZone ): ZonedDateTime = try {
154
- toZonedDateTime(zone )
153
+ private fun Instant.toLocalDateTimeFailing ( offset : UtcOffset ): LocalDateTime = try {
154
+ toLocalDateTimeImpl(offset )
155
155
} catch (e: IllegalArgumentException ) {
156
156
throw DateTimeArithmeticException (" Can not convert instant $this to LocalDateTime to perform computations" , e)
157
157
}
158
158
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].
168
160
* This is done on the results of computations for consistency with other platforms.
169
161
*/
170
162
private fun Instant.check (zone : TimeZone ): Instant = this @check.also {
171
- toZonedDateTimeFailing( zone)
163
+ toLocalDateTimeFailing(offsetIn( zone) )
172
164
}
173
165
174
166
public actual fun Instant.plus (period : DateTimePeriod , timeZone : TimeZone ): Instant = try {
175
167
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
180
186
.run { if (totalNanoseconds != 0L ) plus(0 , totalNanoseconds).check(timeZone) else this }
181
187
}.check(timeZone)
182
188
} catch (e: ArithmeticException ) {
@@ -197,11 +203,9 @@ public actual fun Instant.plus(value: Long, unit: DateTimeUnit, timeZone: TimeZo
197
203
is DateTimeUnit .DateBased -> {
198
204
if (value < Int .MIN_VALUE || value > Int .MAX_VALUE )
199
205
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()
205
209
}
206
210
is DateTimeUnit .TimeBased ->
207
211
check(timeZone).plus(value, unit).check(timeZone)
@@ -224,31 +228,23 @@ public actual fun Instant.plus(value: Long, unit: DateTimeUnit.TimeBased): Insta
224
228
}
225
229
226
230
public 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
244
240
245
241
return buildDateTimePeriod(months, days, nanoseconds)
246
242
}
247
243
248
244
public actual fun Instant.until (other : Instant , unit : DateTimeUnit , timeZone : TimeZone ): Long =
249
245
when (unit) {
250
246
is DateTimeUnit .DateBased ->
251
- toZonedDateTimeFailing( timeZone).dateTime. until(other.toZonedDateTimeFailing( timeZone).dateTime , unit)
247
+ toLocalDateTimeFailing(offsetIn( timeZone)). until(other.toLocalDateTimeFailing(other.offsetIn( timeZone)) , unit)
252
248
.toLong()
253
249
is DateTimeUnit .TimeBased -> {
254
250
check(timeZone); other.check(timeZone)
0 commit comments