@@ -12,13 +12,11 @@ import kotlinx.datetime.internal.*
1212import kotlinx.datetime.serializers.InstantIso8601Serializer
1313import kotlinx.serialization.Serializable
1414import java.time.DateTimeException
15- import java.time.format.DateTimeParseException
16- import java.time.temporal.ChronoUnit
15+ import java.time.temporal.*
1716import kotlin.time.*
1817import kotlin.time.Duration.Companion.nanoseconds
1918import kotlin.time.Duration.Companion.seconds
2019import java.time.Instant as jtInstant
21- import java.time.OffsetDateTime as jtOffsetDateTime
2220import java.time.Clock as jtClock
2321
2422@Serializable(with = InstantIso8601Serializer ::class )
@@ -67,35 +65,23 @@ public actual class Instant internal constructor(internal val value: jtInstant)
6765 public actual fun fromEpochMilliseconds (epochMilliseconds : Long ): Instant =
6866 Instant (jtInstant.ofEpochMilli(epochMilliseconds))
6967
70- public actual fun parse (input : CharSequence , format : DateTimeFormat <DateTimeComponents >): Instant =
71- if (format == = DateTimeComponents .Formats .ISO_DATE_TIME_OFFSET ) {
72- try {
73- Instant (jtOffsetDateTime.parse(fixOffsetRepresentation(input)).toInstant())
74- } catch (e: DateTimeParseException ) {
75- throw DateTimeFormatException (e)
76- }
77- } else {
78- try {
79- format.parse(input).toInstantUsingOffset()
80- } catch (e: IllegalArgumentException ) {
81- throw DateTimeFormatException (" Failed to parse an instant from '$input '" , e)
82- }
83- }
68+ // TODO: implement a custom parser to 1) help DCE get rid of the formatting machinery 2) move Instant to stdlib
69+ public actual fun parse (input : CharSequence , format : DateTimeFormat <DateTimeComponents >): Instant = try {
70+ /* *
71+ * Can't use built-in Java Time's handling of `Instant.parse` because it supports 24:00:00 and
72+ * 23:59:60, and also doesn't support non-`Z` UTC offsets on older JDKs.
73+ * Can't use custom Java Time's formats because Java 8 doesn't support the UTC offset format with
74+ * optional minutes and seconds and `:` between them:
75+ * https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatterBuilder.html#appendOffset-java.lang.String-java.lang.String-
76+ */
77+ format.parse(input).toInstantUsingOffset()
78+ } catch (e: IllegalArgumentException ) {
79+ throw DateTimeFormatException (" Failed to parse an instant from '$input '" , e)
80+ }
8481
8582 @Deprecated(" This overload is only kept for binary compatibility" , level = DeprecationLevel .HIDDEN )
8683 public fun parse (isoString : String ): Instant = parse(input = isoString)
8784
88- /* * A workaround for a quirk of the JDKs older than 11 where the string representations of Instant that have an
89- * offset of the form "+XX" are not recognized by [jtOffsetDateTime.parse], while "+XX:XX" work fine. */
90- private fun fixOffsetRepresentation (isoString : CharSequence ): CharSequence {
91- val time = isoString.indexOf(' T' , ignoreCase = true )
92- if (time == - 1 ) return isoString // the string is malformed
93- val offset = isoString.indexOfLast { c -> c == ' +' || c == ' -' }
94- if (offset < time) return isoString // the offset is 'Z' and not +/- something else
95- val separator = isoString.indexOf(' :' , offset) // if there is a ':' in the offset, no changes needed
96- return if (separator != - 1 ) isoString else " $isoString :00"
97- }
98-
9985 public actual fun fromEpochSeconds (epochSeconds : Long , nanosecondAdjustment : Long ): Instant = try {
10086 Instant (jtInstant.ofEpochSecond(epochSeconds, nanosecondAdjustment))
10187 } catch (e: Exception ) {
0 commit comments