-
Notifications
You must be signed in to change notification settings - Fork 110
/
Copy pathUtcOffsetJvm.kt
91 lines (76 loc) · 3.93 KB
/
UtcOffsetJvm.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/*
* Copyright 2019-2021 JetBrains s.r.o.
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
*/
package kotlinx.datetime
import kotlinx.datetime.format.*
import kotlinx.datetime.serializers.UtcOffsetSerializer
import kotlinx.serialization.Serializable
import java.time.DateTimeException
import java.time.ZoneOffset
import java.time.format.DateTimeFormatterBuilder
import java.time.format.*
@Serializable(with = UtcOffsetSerializer::class)
public actual class UtcOffset(
internal val zoneOffset: ZoneOffset
): java.io.Serializable {
public actual val totalSeconds: Int get() = zoneOffset.totalSeconds
override fun hashCode(): Int = zoneOffset.hashCode()
actual override fun equals(other: Any?): Boolean = other is UtcOffset && this.zoneOffset == other.zoneOffset
actual override fun toString(): String = zoneOffset.toString()
public actual companion object {
public actual val ZERO: UtcOffset = UtcOffset(ZoneOffset.UTC)
public actual fun parse(input: CharSequence, format: DateTimeFormat<UtcOffset>): UtcOffset = when {
format === Formats.ISO -> parseWithFormat(input, isoFormat)
format === Formats.ISO_BASIC -> parseWithFormat(input, isoBasicFormat)
format === Formats.FOUR_DIGITS -> parseWithFormat(input, fourDigitsFormat)
else -> format.parse(input)
}
@Deprecated("This overload is only kept for binary compatibility", level = DeprecationLevel.HIDDEN)
public fun parse(offsetString: String): UtcOffset = parse(input = offsetString)
@Suppress("FunctionName")
public actual fun Format(block: DateTimeFormatBuilder.WithUtcOffset.() -> Unit): DateTimeFormat<UtcOffset> =
UtcOffsetFormat.build(block)
// even though this class uses writeReplace (so serialVersionUID is not needed for a stable serialized form), a
// stable serialVersionUID means exceptions caused by deserialization of malicious streams will be consistent
// (InvalidClassException vs. InvalidObjectException, see MaliciousJvmSerializationTest)
private const val serialVersionUID: Long = -6636773355667981618L
}
public actual object Formats {
public actual val ISO: DateTimeFormat<UtcOffset> get() = ISO_OFFSET
public actual val ISO_BASIC: DateTimeFormat<UtcOffset> get() = ISO_OFFSET_BASIC
public actual val FOUR_DIGITS: DateTimeFormat<UtcOffset> get() = FOUR_DIGIT_OFFSET
}
private fun readObject(ois: java.io.ObjectInputStream): Unit =
throw java.io.InvalidObjectException("kotlinx.datetime.UtcOffset must be deserialized via kotlinx.datetime.Ser")
private fun writeReplace(): Any = Ser(Ser.UTC_OFFSET_TAG, this)
}
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
public actual fun UtcOffset(hours: Int? = null, minutes: Int? = null, seconds: Int? = null): UtcOffset =
try {
when {
hours != null ->
UtcOffset(ZoneOffset.ofHoursMinutesSeconds(hours, minutes ?: 0, seconds ?: 0))
minutes != null ->
UtcOffset(ZoneOffset.ofHoursMinutesSeconds(minutes / 60, minutes % 60, seconds ?: 0))
else -> {
UtcOffset(ZoneOffset.ofTotalSeconds(seconds ?: 0))
}
}
} catch (e: DateTimeException) {
throw IllegalArgumentException(e)
}
private val isoFormat by lazy {
DateTimeFormatterBuilder().parseCaseInsensitive().appendOffsetId().toFormatter()
}
private val isoBasicFormat by lazy {
DateTimeFormatterBuilder().parseCaseInsensitive().appendOffset("+HHmmss", "Z").toFormatter()
}
private val fourDigitsFormat by lazy {
DateTimeFormatterBuilder().parseCaseInsensitive().appendOffset("+HHMM", "+0000").toFormatter()
}
private fun parseWithFormat(input: CharSequence, format: DateTimeFormatter) = try {
format.parse(input, ZoneOffset::from).let(::UtcOffset)
} catch (e: DateTimeException) {
throw DateTimeFormatException(e)
}