Skip to content

Split ZoneOffset into UtcOffset and FixedOffsetTimeZone #125

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jul 2, 2021
Merged

Conversation

ilya-g
Copy link
Member

@ilya-g ilya-g commented Jun 4, 2021

This PR separates the concept of a time zone with a fixed UTC offset and from the concept of UTC offset itself.

Remaining task items:

  • serialization of UtcOffset
  • decide on UtcOffset normalization
  • make UtcOffset comparable
    • decide on the default ordering

Work postponed for a further PR:

@ilya-g ilya-g marked this pull request as ready for review June 8, 2021 14:08
@ilya-g ilya-g requested a review from dkhalanskyjb June 8, 2021 14:08
encoder.encodeString(value.id)
}

}

public object UtcOffsetSerializer: KSerializer<UtcOffset> {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could also provide an alternative serializer that stores offset as an integer primitive or a single component object.

@ilya-g ilya-g force-pushed the utc-offset branch 2 times, most recently from dd35124 to 6e0f75c Compare June 21, 2021 15:05
@@ -28,12 +27,12 @@ public actual open class TimeZone internal constructor(internal val zoneId: Zone

public actual companion object {
public actual fun currentSystemDefault(): TimeZone = ZoneId.systemDefault().let(::TimeZone)
public actual val UTC: TimeZone = jtZoneOffset.UTC.let(::TimeZone)
public actual val UTC: FixedOffsetTimeZone = UtcOffset(jtZoneOffset.UTC).asTimeZone()

public actual fun of(zoneId: String): TimeZone = try {
val zone = ZoneId.of(zoneId)
if (zone is jtZoneOffset) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't we want to do zone.rules.isFixedOffset here instead and normalize the fixed-offset time zones? You said that this would be in the following PR. Keeping the message for the following note:

By the way, somewhat bad news: 310bp implements isFixedOffset as follows:

    public boolean isFixedOffset() {
        return savingsInstantTransitions.length == 0;
    }

So, I think this means that there is no way to discern the inherently fixed-offset time zones from those that are simply yet to have their first transition.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any examples of such time zones?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not that I know of.


override fun hashCode(): Int = zoneOffset.hashCode().toInt()
override fun equals(other: Any?): Boolean = other is UtcOffset && this.zoneOffset == other.zoneOffset
override fun toString(): String = zoneOffset.toString()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the Native implementation, these methods are simple and seemingly don't gain anything by being delegated to ZoneOffset, so I don't see a reason to store that as opposed to just a plain number of seconds.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd keep ZoneOffset instance for interop with js-joda library.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

js-joda caches ZoneOffset instances: https://github.com/js-joda/js-joda/blob/master/packages/core/src/ZoneOffset.js#L287, so I don't think constructing ZoneOffset on the fly in the converter functions could become a bottleneck.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same goes for the Java implementation.


public actual fun Instant.toLocalDateTime(timeZone: TimeZone): LocalDateTime = try {
java.time.LocalDateTime.ofInstant(this.value, timeZone.zoneId).let(::LocalDateTime)
} catch (e: DateTimeException) {
throw DateTimeArithmeticException(e)
}

internal actual fun Instant.toLocalDateTime(offset: UtcOffset): LocalDateTime = try {
java.time.LocalDateTime.ofInstant(this.value, offset.zoneOffset).let(::LocalDateTime)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we do decide not to store a ZoneOffset inside a UtcOffset, then LocalDateTime.ofEpochSecond would probably fit better here.

val zone = TimeZone.of(decoder.decodeString())
if (zone is ZoneOffset) {
if (zone is FixedOffsetTimeZone) {
return zone
} else {
throw SerializationException("Timezone identifier '$zone' does not correspond to a fixed-offset timezone")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be a problem if a time zone is recognized as fixed-offset in one platform, but not as fixed-offset in other.

@ilya-g ilya-g force-pushed the utc-offset branch 2 times, most recently from c01b720 to 88f8ca3 Compare July 2, 2021 15:04
ilya-g added 11 commits July 2, 2021 18:06
Extract some former native-only ZoneOffset tests into common UtcOffset tests.
On the contrary, two FixedOffsetTimeZones with the same offset can differ by id
(this aspect is native-only for now).
Roundtripping zone names when converting FixedOffsetTimeZone to NSTimeZone and back
is not guaranteed. Instead ensure that the returned time zone is a FixedOffsetTimeZone
and has the same offset.
Override some methods in FixedOffsetTimeZone to provide a simpler implementation
@ilya-g ilya-g added this to the 0.3.0 milestone Jul 2, 2021
@ilya-g ilya-g merged commit a35ae66 into master Jul 2, 2021
public fun parse(offsetString: String): UtcOffset
}
}
public expect fun UtcOffset(hours: Int? = null, minutes: Int? = null, seconds: Int? = null): UtcOffset
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be documented. The other new functions as well, but the rest of them are much more self-explanatory.

@ilya-g ilya-g deleted the utc-offset branch September 29, 2021 15:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants