Skip to content

Commit 651f254

Browse files
committed
UtcOffset serialization (as a string primitive)
1 parent 32182ad commit 651f254

File tree

7 files changed

+64
-2
lines changed

7 files changed

+64
-2
lines changed

core/common/src/TimeZone.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ package kotlinx.datetime
1010

1111
import kotlinx.datetime.serializers.TimeZoneSerializer
1212
import kotlinx.datetime.serializers.FixedOffsetTimeZoneSerializer
13+
import kotlinx.datetime.serializers.UtcOffsetSerializer
1314
import kotlinx.serialization.Serializable
1415

1516
@Serializable(with = TimeZoneSerializer::class)
@@ -97,6 +98,7 @@ public expect class FixedOffsetTimeZone : TimeZone {
9798
@Deprecated("Use FixedOffsetTimeZone of UtcOffset instead", ReplaceWith("FixedOffsetTimeZone"))
9899
public typealias ZoneOffset = FixedOffsetTimeZone
99100

101+
@Serializable(with = UtcOffsetSerializer::class)
100102
public expect class UtcOffset {
101103
public val totalSeconds: Int
102104

core/common/src/serializers/TimeZoneSerializers.kt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package kotlinx.datetime.serializers
77

88
import kotlinx.datetime.FixedOffsetTimeZone
99
import kotlinx.datetime.TimeZone
10+
import kotlinx.datetime.UtcOffset
1011
import kotlinx.serialization.*
1112
import kotlinx.serialization.descriptors.*
1213
import kotlinx.serialization.encoding.*
@@ -25,7 +26,7 @@ public object TimeZoneSerializer: KSerializer<TimeZone> {
2526

2627
public object FixedOffsetTimeZoneSerializer: KSerializer<FixedOffsetTimeZone> {
2728

28-
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ZoneOffset", PrimitiveKind.STRING)
29+
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("FixedOffsetTimeZone", PrimitiveKind.STRING)
2930

3031
override fun deserialize(decoder: Decoder): FixedOffsetTimeZone {
3132
val zone = TimeZone.of(decoder.decodeString())
@@ -41,3 +42,17 @@ public object FixedOffsetTimeZoneSerializer: KSerializer<FixedOffsetTimeZone> {
4142
}
4243

4344
}
45+
46+
public object UtcOffsetSerializer: KSerializer<UtcOffset> {
47+
48+
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("UtcOffset", PrimitiveKind.STRING)
49+
50+
override fun deserialize(decoder: Decoder): UtcOffset {
51+
return UtcOffset.parse(decoder.decodeString())
52+
}
53+
54+
override fun serialize(encoder: Encoder, value: UtcOffset) {
55+
encoder.encodeString(value.toString())
56+
}
57+
58+
}

core/js/src/TimeZone.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package kotlinx.datetime
77
import kotlinx.datetime.internal.JSJoda.ZoneId
88
import kotlinx.datetime.serializers.TimeZoneSerializer
99
import kotlinx.datetime.serializers.FixedOffsetTimeZoneSerializer
10+
import kotlinx.datetime.serializers.UtcOffsetSerializer
1011
import kotlinx.serialization.Serializable
1112
import kotlinx.datetime.internal.JSJoda.ZoneOffset as jtZoneOffset
1213

@@ -54,6 +55,7 @@ public actual class FixedOffsetTimeZone actual constructor(public actual val utc
5455
public actual val totalSeconds: Int get() = zoneOffset.totalSeconds().toInt()
5556
}
5657

58+
@Serializable(with = UtcOffsetSerializer::class)
5759
public actual class UtcOffset(internal val zoneOffset: jtZoneOffset) {
5860
public actual val totalSeconds: Int get() = zoneOffset.totalSeconds().toInt()
5961

core/jvm/src/TimeZoneJvm.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ package kotlinx.datetime
1010

1111
import kotlinx.datetime.serializers.TimeZoneSerializer
1212
import kotlinx.datetime.serializers.FixedOffsetTimeZoneSerializer
13+
import kotlinx.datetime.serializers.UtcOffsetSerializer
1314
import kotlinx.serialization.Serializable
1415
import java.time.DateTimeException
1516
import java.time.ZoneId
@@ -58,6 +59,7 @@ public actual constructor(public actual val utcOffset: UtcOffset): TimeZone(utcO
5859
public actual val totalSeconds: Int get() = utcOffset.totalSeconds
5960
}
6061

62+
@Serializable(with = UtcOffsetSerializer::class)
6163
public actual class UtcOffset(internal val zoneOffset: jtZoneOffset) {
6264
public actual val totalSeconds: Int get() = zoneOffset.totalSeconds
6365

core/native/src/TimeZone.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ package kotlinx.datetime
1010

1111
import kotlinx.datetime.serializers.TimeZoneSerializer
1212
import kotlinx.datetime.serializers.FixedOffsetTimeZoneSerializer
13+
import kotlinx.datetime.serializers.UtcOffsetSerializer
1314
import kotlin.math.abs
1415
import kotlin.native.concurrent.*
1516
import kotlinx.serialization.Serializable
@@ -105,6 +106,7 @@ public actual class FixedOffsetTimeZone internal constructor(public actual val u
105106
}
106107

107108

109+
@Serializable(with = UtcOffsetSerializer::class)
108110
public actual class UtcOffset internal constructor(public actual val totalSeconds: Int) {
109111
private val id: String = zoneIdByOffset(totalSeconds)
110112

serialization/common/test/TimeZoneSerializationTest.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,5 @@ class TimeZoneSerializationTest {
4949
zoneOffsetSerialization(Json.serializersModule.serializer())
5050
serialization(Json.serializersModule.serializer())
5151
}
52-
}
52+
}
53+
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2019-2021 JetBrains s.r.o.
3+
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
4+
*/
5+
6+
package kotlinx.datetime.serialization.test
7+
8+
import kotlinx.datetime.*
9+
import kotlinx.datetime.serializers.*
10+
import kotlinx.serialization.KSerializer
11+
import kotlinx.serialization.json.*
12+
import kotlinx.serialization.serializer
13+
import kotlin.test.*
14+
15+
class UtcOffsetSerializationTest {
16+
17+
private fun testSerializationAsPrimitive(serializer: KSerializer<UtcOffset>) {
18+
val offset2h = UtcOffset.parse("+2")
19+
assertEquals("\"+02:00\"", Json.encodeToString(serializer, offset2h))
20+
assertEquals(offset2h, Json.decodeFromString(serializer, "\"+02:00\""))
21+
assertEquals(offset2h, Json.decodeFromString(serializer, "\"+02\""))
22+
assertEquals(offset2h, Json.decodeFromString(serializer, "\"+2\""))
23+
24+
assertFailsWith<IllegalArgumentException> {
25+
Json.decodeFromString(serializer, "\"UTC+02:00\"") // not an offset
26+
}
27+
}
28+
29+
@Test
30+
fun defaultSerializer() {
31+
testSerializationAsPrimitive(Json.serializersModule.serializer())
32+
}
33+
34+
@Test
35+
fun stringPrimitiveSerializer() {
36+
testSerializationAsPrimitive(UtcOffsetSerializer)
37+
}
38+
}

0 commit comments

Comments
 (0)