@@ -14,14 +14,21 @@ import kotlin.math.roundToLong
14
14
private val tzdb: Result <TimeZoneDatabase ?> = runCatching {
15
15
/* *
16
16
* References:
17
+ * - <https://momentjs.com/timezone/docs/#/data-formats/packed-format/>
17
18
* - https://github.com/js-joda/js-joda/blob/8c1a7448db92ca014417346049fb64b55f7b1ac1/packages/timezone/src/MomentZoneRulesProvider.js#L78-L94
18
19
* - https://github.com/js-joda/js-joda/blob/8c1a7448db92ca014417346049fb64b55f7b1ac1/packages/timezone/src/unpack.js
19
20
* - <https://momentjs.com/timezone/docs/#/zone-object/>
20
21
*/
22
+ fun charCodeToInt (char : Char ): Int = when (char) {
23
+ in ' 0' .. ' 9' -> char - ' 0'
24
+ in ' a' .. ' z' -> char - ' a' + 10
25
+ in ' A' .. ' X' -> char - ' A' + 36
26
+ else -> throw IllegalArgumentException (" Invalid character: $char " )
27
+ }
21
28
fun unpackBase60 (string : String ): Double {
22
29
var i = 0
23
30
var parts = string.split(' .' )
24
- var whole = parts[0 ]
31
+ val whole = parts[0 ]
25
32
var multiplier = 1.0
26
33
var out = 0.0
27
34
var sign = 1
@@ -32,14 +39,6 @@ private val tzdb: Result<TimeZoneDatabase?> = runCatching {
32
39
sign = - 1
33
40
}
34
41
35
- fun charCodeToInt (char : Char ): Int =
36
- when (char) {
37
- in ' 0' .. ' 9' -> char - ' 0'
38
- in ' a' .. ' z' -> char - ' a' + 10
39
- in ' A' .. ' X' -> char - ' A' + 36
40
- else -> throw IllegalArgumentException (" Invalid character: $char " )
41
- }
42
-
43
42
// handle digits before the decimal
44
43
for (ix in i.. whole.lastIndex) {
45
44
out = 60 * out + charCodeToInt(whole[ix])
@@ -56,28 +55,18 @@ private val tzdb: Result<TimeZoneDatabase?> = runCatching {
56
55
return out * sign
57
56
}
58
57
59
- fun <T , R > List<T>.scanWithoutInitial (initial : R , operation : (acc: R , T ) -> R ): List <R > = buildList {
60
- var accumulator = initial
61
- for (element in this @scanWithoutInitial) {
62
- accumulator = operation(accumulator, element)
63
- add(accumulator)
64
- }
65
- }
66
-
67
- fun List<Long>.partialSums (): List <Long > = scanWithoutInitial(0 , Long ::plus)
68
-
69
58
val zones = mutableMapOf<String , TimeZoneRules >()
70
59
val (zonesPacked, linksPacked) = readTzdb() ? : return @runCatching null
71
60
for (zone in zonesPacked) {
72
61
val components = zone.split(' |' )
73
62
val offsets = components[2 ].split(' ' ).map { unpackBase60(it) }
74
- val indices = components[3 ].map { it - ' 0 ' }
63
+ val indices = components[3 ].map { charCodeToInt(it) }
75
64
val lengthsOfPeriodsWithOffsets = components[4 ].split(' ' ).map {
76
65
(unpackBase60(it) * SECONDS_PER_MINUTE * MILLIS_PER_ONE ).roundToLong() / // minutes to milliseconds
77
66
MILLIS_PER_ONE // but we only need seconds
78
67
}
79
68
zones[components[0 ]] = TimeZoneRules (
80
- transitionEpochSeconds = lengthsOfPeriodsWithOffsets.partialSums( ).take<Long >(indices.size - 1 ),
69
+ transitionEpochSeconds = lengthsOfPeriodsWithOffsets.runningReduce( Long ::plus ).take<Long >(indices.size - 1 ),
81
70
offsets = indices.map { UtcOffset (null , null , - (offsets[it] * 60 ).roundToInt()) },
82
71
recurringZoneRules = null
83
72
)
0 commit comments