Skip to content

Commit 44b8ee3

Browse files
committed
Refactor native TimeZoneImpl
- Remove need in ZoneOffsetImpl wrapping UtcOffset - Remove the interface TimeZoneImpl and merge it into RegionTimeZone class
1 parent d06c37b commit 44b8ee3

File tree

5 files changed

+59
-95
lines changed

5 files changed

+59
-95
lines changed

core/darwin/src/TimeZoneNative.kt

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,17 @@ private fun systemDateByLocalDate(zone: NSTimeZone, localDate: NSDate): NSDate?
2626
return iso8601.dateFromComponents(dateComponents)
2727
}
2828

29-
internal actual class PlatformTimeZoneImpl(private val value: NSTimeZone, override val id: String): TimeZoneImpl {
29+
internal actual class RegionTimeZone(private val value: NSTimeZone, actual override val id: String): TimeZone() {
3030
actual companion object {
31-
actual fun of(zoneId: String): PlatformTimeZoneImpl {
31+
actual fun of(zoneId: String): RegionTimeZone {
3232
val abbreviations = NSTimeZone.abbreviationDictionary
3333
val trueZoneId = abbreviations[zoneId] as String? ?: zoneId
3434
val zone = NSTimeZone.timeZoneWithName(trueZoneId)
3535
?: throw IllegalTimeZoneException("No timezone found with zone ID '$zoneId'")
36-
return PlatformTimeZoneImpl(zone, zoneId)
36+
return RegionTimeZone(zone, zoneId)
3737
}
3838

39-
actual fun currentSystemDefault(): PlatformTimeZoneImpl {
39+
actual fun currentSystemDefault(): RegionTimeZone {
4040
/* The framework has its own cache of the system timezone. Calls to
4141
[NSTimeZone systemTimeZone] do not reflect changes to the system timezone
4242
and instead just return the cached value. Thus, to acquire the current
@@ -86,7 +86,7 @@ internal actual class PlatformTimeZoneImpl(private val value: NSTimeZone, overri
8686
*/
8787
NSTimeZone.resetSystemTimeZone()
8888
val zone = NSTimeZone.systemTimeZone
89-
return PlatformTimeZoneImpl(zone, zone.name)
89+
return RegionTimeZone(zone, zone.name)
9090
}
9191

9292
actual val availableZoneIds: Set<String>
@@ -110,7 +110,7 @@ internal actual class PlatformTimeZoneImpl(private val value: NSTimeZone, overri
110110
}
111111
}
112112

113-
override fun atStartOfDay(date: LocalDate): Instant {
113+
actual override fun atStartOfDay(date: LocalDate): Instant {
114114
val ldt = LocalDateTime(date, LocalTime.MIN)
115115
val epochSeconds = ldt.toEpochSecond(UtcOffset.ZERO)
116116
// timezone
@@ -132,15 +132,15 @@ internal actual class PlatformTimeZoneImpl(private val value: NSTimeZone, overri
132132
return Instant(midnight.timeIntervalSince1970.toLong(), 0)
133133
}
134134

135-
override fun atZone(dateTime: LocalDateTime, preferred: UtcOffset?): ZonedDateTime {
135+
actual override fun atZone(dateTime: LocalDateTime, preferred: UtcOffset?): ZonedDateTime {
136136
val epochSeconds = dateTime.toEpochSecond(UtcOffset.ZERO)
137137
var offset = preferred?.totalSeconds ?: Int.MAX_VALUE
138138
val transitionDuration = run {
139139
/* a date in an unspecified timezone, defined by the number of seconds since
140140
the start of the epoch in *that* unspecified timezone */
141141
val date = dateWithTimeIntervalSince1970Saturating(epochSeconds)
142142
val newDate = systemDateByLocalDate(value, date)
143-
?: throw RuntimeException("Unable to acquire the offset at $dateTime for zone ${this@PlatformTimeZoneImpl}")
143+
?: throw RuntimeException("Unable to acquire the offset at $dateTime for zone ${this@RegionTimeZone}")
144144
// we now know the offset of that timezone at this time.
145145
offset = value.secondsFromGMTForDate(newDate).toInt()
146146
/* `dateFromComponents` automatically corrects the date to avoid gaps. We
@@ -155,23 +155,14 @@ internal actual class PlatformTimeZoneImpl(private val value: NSTimeZone, overri
155155
} catch (e: ArithmeticException) {
156156
throw RuntimeException("Anomalously long timezone transition gap reported", e)
157157
}
158-
return ZonedDateTime(correctedDateTime, TimeZone(this), UtcOffset.ofSeconds(offset))
158+
return ZonedDateTime(correctedDateTime, this@RegionTimeZone, UtcOffset.ofSeconds(offset))
159159
}
160160

161-
override fun offsetAt(instant: Instant): UtcOffset {
161+
actual override fun offsetAtImpl(instant: Instant): UtcOffset {
162162
val date = dateWithTimeIntervalSince1970Saturating(instant.epochSeconds)
163163
return UtcOffset.ofSeconds(value.secondsFromGMTForDate(date).toInt())
164164
}
165165

166-
// org.threeten.bp.ZoneId#equals
167-
override fun equals(other: Any?): Boolean =
168-
this === other || other is PlatformTimeZoneImpl && this.id == other.id
169-
170-
// org.threeten.bp.ZoneId#hashCode
171-
override fun hashCode(): Int = id.hashCode()
172-
173-
// org.threeten.bp.ZoneId#toString
174-
override fun toString(): String = id
175166
}
176167

177168
internal actual fun currentTime(): Instant = NSDate.date().toKotlinInstant()

core/darwin/test/ConvertersTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class ConvertersTest {
4848
for (id in TimeZone.availableZoneIds) {
4949
val normalizedId = (NSTimeZone.abbreviationDictionary[id] ?: id) as String
5050
val timeZone = TimeZone.of(normalizedId)
51-
if (timeZone.value is ZoneOffsetImpl) {
51+
if (timeZone is FixedOffsetTimeZone) {
5252
continue
5353
}
5454
val nsTimeZone = timeZone.toNSTimeZone()

core/native/cinterop_actuals/TimeZoneNative.kt

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,23 @@ import kotlinx.datetime.internal.*
88
import kotlinx.cinterop.*
99
import platform.posix.free
1010

11-
internal actual class PlatformTimeZoneImpl(private val tzid: TZID, override val id: String): TimeZoneImpl {
11+
internal actual class RegionTimeZone(private val tzid: TZID, actual override val id: String): TimeZone() {
1212
actual companion object {
13-
actual fun of(zoneId: String): PlatformTimeZoneImpl {
13+
actual fun of(zoneId: String): RegionTimeZone {
1414
val tzid = timezone_by_name(zoneId)
1515
if (tzid == TZID_INVALID) {
1616
throw IllegalTimeZoneException("No timezone found with zone ID '$zoneId'")
1717
}
18-
return PlatformTimeZoneImpl(tzid, zoneId)
18+
return RegionTimeZone(tzid, zoneId)
1919
}
2020

21-
actual fun currentSystemDefault(): PlatformTimeZoneImpl = memScoped {
21+
actual fun currentSystemDefault(): RegionTimeZone = memScoped {
2222
val tzid = alloc<TZIDVar>()
2323
val string = get_system_timezone(tzid.ptr)
2424
?: throw RuntimeException("Failed to get the system timezone.")
2525
val kotlinString = string.toKString()
2626
free(string)
27-
PlatformTimeZoneImpl(tzid.value, kotlinString)
27+
RegionTimeZone(tzid.value, kotlinString)
2828
}
2929

3030
actual val availableZoneIds: Set<String>
@@ -45,7 +45,7 @@ internal actual class PlatformTimeZoneImpl(private val tzid: TZID, override val
4545
}
4646
}
4747

48-
override fun atStartOfDay(date: LocalDate): Instant = memScoped {
48+
actual override fun atStartOfDay(date: LocalDate): Instant = memScoped {
4949
val ldt = LocalDateTime(date, LocalTime.MIN)
5050
val epochSeconds = ldt.toEpochSecond(UtcOffset.ZERO)
5151
val midnightInstantSeconds = at_start_of_day(tzid, epochSeconds)
@@ -55,13 +55,13 @@ internal actual class PlatformTimeZoneImpl(private val tzid: TZID, override val
5555
Instant(midnightInstantSeconds, 0)
5656
}
5757

58-
override fun atZone(dateTime: LocalDateTime, preferred: UtcOffset?): ZonedDateTime = memScoped {
58+
actual override fun atZone(dateTime: LocalDateTime, preferred: UtcOffset?): ZonedDateTime = memScoped {
5959
val epochSeconds = dateTime.toEpochSecond(UtcOffset.ZERO)
6060
val offset = alloc<IntVar>()
6161
offset.value = preferred?.totalSeconds ?: Int.MAX_VALUE
6262
val transitionDuration = offset_at_datetime(tzid, epochSeconds, offset.ptr)
6363
if (offset.value == Int.MAX_VALUE) {
64-
throw RuntimeException("Unable to acquire the offset at $dateTime for zone ${this@PlatformTimeZoneImpl}")
64+
throw RuntimeException("Unable to acquire the offset at $dateTime for zone ${this@RegionTimeZone}")
6565
}
6666
val correctedDateTime = try {
6767
dateTime.plusSeconds(transitionDuration)
@@ -70,26 +70,17 @@ internal actual class PlatformTimeZoneImpl(private val tzid: TZID, override val
7070
} catch (e: ArithmeticException) {
7171
throw RuntimeException("Anomalously long timezone transition gap reported", e)
7272
}
73-
ZonedDateTime(correctedDateTime, TimeZone(this@PlatformTimeZoneImpl), UtcOffset.ofSeconds(offset.value))
73+
ZonedDateTime(correctedDateTime, this@RegionTimeZone, UtcOffset.ofSeconds(offset.value))
7474
}
7575

76-
override fun offsetAt(instant: Instant): UtcOffset {
76+
actual override fun offsetAtImpl(instant: Instant): UtcOffset {
7777
val offset = offset_at_instant(tzid, instant.epochSeconds)
7878
if (offset == Int.MAX_VALUE) {
7979
throw RuntimeException("Unable to acquire the offset at instant $instant for zone $this")
8080
}
8181
return UtcOffset.ofSeconds(offset)
8282
}
8383

84-
// org.threeten.bp.ZoneId#equals
85-
override fun equals(other: Any?): Boolean =
86-
this === other || other is PlatformTimeZoneImpl && this.id == other.id
87-
88-
// org.threeten.bp.ZoneId#hashCode
89-
override fun hashCode(): Int = id.hashCode()
90-
91-
// org.threeten.bp.ZoneId#toString
92-
override fun toString(): String = id
9384
}
9485

9586
internal actual fun currentTime(): Instant = memScoped {

core/native/src/TimeZone.kt

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@ import kotlinx.datetime.serializers.*
1212
import kotlinx.serialization.Serializable
1313

1414
@Serializable(with = TimeZoneSerializer::class)
15-
public actual open class TimeZone internal constructor(internal val value: TimeZoneImpl) {
15+
public actual open class TimeZone internal constructor() {
1616

1717
public actual companion object {
1818

19-
public actual fun currentSystemDefault(): TimeZone = PlatformTimeZoneImpl.currentSystemDefault().let(::TimeZone)
19+
public actual fun currentSystemDefault(): TimeZone =
20+
// TODO: probably check if currentSystemDefault name is parseable as FixedOffsetTimeZone?
21+
RegionTimeZone.currentSystemDefault()
2022

2123
public actual val UTC: FixedOffsetTimeZone = UtcOffset.ZERO.asTimeZone()
2224

@@ -56,23 +58,24 @@ public actual open class TimeZone internal constructor(internal val value: TimeZ
5658
} catch (e: DateTimeFormatException) {
5759
throw IllegalTimeZoneException(e)
5860
}
59-
return TimeZone(PlatformTimeZoneImpl.of(zoneId))
61+
return RegionTimeZone.of(zoneId)
6062
}
6163

6264
public actual val availableZoneIds: Set<String>
63-
get() = PlatformTimeZoneImpl.availableZoneIds
65+
get() = RegionTimeZone.availableZoneIds
6466
}
6567

66-
public actual val id: String
67-
get() = value.id
68+
public actual open val id: String
69+
get() = error("Should be overridden")
6870

6971
public actual fun Instant.toLocalDateTime(): LocalDateTime = instantToLocalDateTime(this)
7072
public actual fun LocalDateTime.toInstant(): Instant = localDateTimeToInstant(this)
7173

72-
internal open fun atStartOfDay(date: LocalDate): Instant = value.atStartOfDay(date)
74+
internal open fun atStartOfDay(date: LocalDate): Instant = error("Should be overridden") //value.atStartOfDay(date)
75+
internal open fun offsetAtImpl(instant: Instant): UtcOffset = error("Should be overridden")
7376

7477
internal open fun instantToLocalDateTime(instant: Instant): LocalDateTime = try {
75-
instant.toLocalDateTimeImpl(offsetAt(instant))
78+
instant.toLocalDateTimeImpl(offsetAtImpl(instant))
7679
} catch (e: IllegalArgumentException) {
7780
throw DateTimeArithmeticException("Instant $instant is not representable as LocalDateTime.", e)
7881
}
@@ -81,32 +84,53 @@ public actual open class TimeZone internal constructor(internal val value: TimeZ
8184
atZone(dateTime).toInstant()
8285

8386
internal open fun atZone(dateTime: LocalDateTime, preferred: UtcOffset? = null): ZonedDateTime =
84-
value.atZone(dateTime, preferred)
87+
error("Should be overridden")
8588

8689
override fun equals(other: Any?): Boolean =
87-
this === other || other is TimeZone && this.value == other.value
90+
this === other || other is TimeZone && this.id == other.id
8891

89-
override fun hashCode(): Int = value.hashCode()
92+
override fun hashCode(): Int = id.hashCode()
9093

91-
override fun toString(): String = value.toString()
94+
override fun toString(): String = id
95+
}
96+
97+
internal expect class RegionTimeZone : TimeZone {
98+
override val id: String
99+
override fun atStartOfDay(date: LocalDate): Instant
100+
override fun offsetAtImpl(instant: Instant): UtcOffset
101+
override fun atZone(dateTime: LocalDateTime, preferred: UtcOffset?): ZonedDateTime
102+
103+
companion object {
104+
fun of(zoneId: String): RegionTimeZone
105+
fun currentSystemDefault(): RegionTimeZone
106+
val availableZoneIds: Set<String>
107+
}
92108
}
93109

94110

95111
@Serializable(with = FixedOffsetTimeZoneSerializer::class)
96-
public actual class FixedOffsetTimeZone internal constructor(public actual val offset: UtcOffset, id: String) : TimeZone(ZoneOffsetImpl(offset, id)) {
112+
public actual class FixedOffsetTimeZone internal constructor(public actual val offset: UtcOffset, override val id: String) : TimeZone() {
97113

98114
public actual constructor(offset: UtcOffset) : this(offset, offset.toString())
99115

100116
@Deprecated("Use offset.totalSeconds", ReplaceWith("offset.totalSeconds"))
101117
public actual val totalSeconds: Int get() = offset.totalSeconds
102118

119+
override fun atStartOfDay(date: LocalDate): Instant =
120+
LocalDateTime(date, LocalTime.MIN).toInstant(offset)
121+
122+
override fun offsetAtImpl(instant: Instant): UtcOffset = offset
123+
124+
override fun atZone(dateTime: LocalDateTime, preferred: UtcOffset?): ZonedDateTime =
125+
ZonedDateTime(dateTime, this, offset)
126+
103127
override fun instantToLocalDateTime(instant: Instant): LocalDateTime = instant.toLocalDateTime(offset)
104128
override fun localDateTimeToInstant(dateTime: LocalDateTime): Instant = dateTime.toInstant(offset)
105129
}
106130

107131

108132
public actual fun TimeZone.offsetAt(instant: Instant): UtcOffset =
109-
value.offsetAt(instant)
133+
offsetAtImpl(instant)
110134

111135
public actual fun Instant.toLocalDateTime(timeZone: TimeZone): LocalDateTime =
112136
timeZone.instantToLocalDateTime(this)

core/native/src/TimeZoneImpl.kt

Lines changed: 0 additions & 42 deletions
This file was deleted.

0 commit comments

Comments
 (0)