@@ -14,14 +14,21 @@ import kotlin.math.roundToLong
1414private val tzdb: Result <TimeZoneDatabase ?> = runCatching {
1515 /* *
1616 * References:
17+ * - <https://momentjs.com/timezone/docs/#/data-formats/packed-format/>
1718 * - https://github.com/js-joda/js-joda/blob/8c1a7448db92ca014417346049fb64b55f7b1ac1/packages/timezone/src/MomentZoneRulesProvider.js#L78-L94
1819 * - https://github.com/js-joda/js-joda/blob/8c1a7448db92ca014417346049fb64b55f7b1ac1/packages/timezone/src/unpack.js
1920 * - <https://momentjs.com/timezone/docs/#/zone-object/>
2021 */
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+ }
2128 fun unpackBase60 (string : String ): Double {
2229 var i = 0
2330 var parts = string.split(' .' )
24- var whole = parts[0 ]
31+ val whole = parts[0 ]
2532 var multiplier = 1.0
2633 var out = 0.0
2734 var sign = 1
@@ -32,14 +39,6 @@ private val tzdb: Result<TimeZoneDatabase?> = runCatching {
3239 sign = - 1
3340 }
3441
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-
4342 // handle digits before the decimal
4443 for (ix in i.. whole.lastIndex) {
4544 out = 60 * out + charCodeToInt(whole[ix])
@@ -56,28 +55,18 @@ private val tzdb: Result<TimeZoneDatabase?> = runCatching {
5655 return out * sign
5756 }
5857
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-
6958 val zones = mutableMapOf<String , TimeZoneRules >()
7059 val (zonesPacked, linksPacked) = readTzdb() ? : return @runCatching null
7160 for (zone in zonesPacked) {
7261 val components = zone.split(' |' )
7362 val offsets = components[2 ].split(' ' ).map { unpackBase60(it) }
74- val indices = components[3 ].map { it - ' 0 ' }
63+ val indices = components[3 ].map { charCodeToInt(it) }
7564 val lengthsOfPeriodsWithOffsets = components[4 ].split(' ' ).map {
7665 (unpackBase60(it) * SECONDS_PER_MINUTE * MILLIS_PER_ONE ).roundToLong() / // minutes to milliseconds
7766 MILLIS_PER_ONE // but we only need seconds
7867 }
7968 zones[components[0 ]] = TimeZoneRules (
80- transitionEpochSeconds = lengthsOfPeriodsWithOffsets.partialSums( ).take<Long >(indices.size - 1 ),
69+ transitionEpochSeconds = lengthsOfPeriodsWithOffsets.runningReduce( Long ::plus ).take<Long >(indices.size - 1 ),
8170 offsets = indices.map { UtcOffset (null , null , - (offsets[it] * 60 ).roundToInt()) },
8271 recurringZoneRules = null
8372 )
0 commit comments