Skip to content

Commit 1cb9cdb

Browse files
authored
Disable tests for one more timezone (#424)
Additionally, we changed how some edge cases are handled when attempting to make the timezone work properly. This didn't help, but the new code seems more correct, so we keep the changes.
1 parent 73b7afa commit 1cb9cdb

File tree

3 files changed

+61
-3
lines changed

3 files changed

+61
-3
lines changed

core/native/src/internal/TimeZoneRules.kt

+15
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,21 @@ internal class TimeZoneRules(
115115
val offsetAfter = offsets[transitionIndex + 1]
116116
return OffsetInfo(transitionInstant, offsetBefore, offsetAfter)
117117
}
118+
119+
override fun toString(): String = buildString {
120+
for (i in transitionEpochSeconds.indices) {
121+
append(offsets[i])
122+
append(" until ")
123+
append(Instant.fromEpochSeconds(transitionEpochSeconds[i]))
124+
append(", ")
125+
}
126+
append("then ")
127+
append(offsets.last())
128+
if (recurringZoneRules != null) {
129+
append(", after that ")
130+
append(recurringZoneRules)
131+
}
132+
}
118133
}
119134

120135
internal class RecurringZoneRules(

core/windows/src/internal/TzdbInRegistry.kt

+10-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,16 @@ internal class TzdbInRegistry: TimeZoneDatabase {
6060
}
6161
}
6262
}
63-
if (offsets.isEmpty()) { offsets.add(recurring.offsetAtYearStart()) }
63+
offsets.lastOrNull()?.let { lastOffset ->
64+
/* If there are already some offsets, we can not add a new offset without defining a transition to
65+
it. The moment when we start using the recurring rules is the first year that does not have any
66+
historic data provided. */
67+
val firstYearWithRecurringRules = historic.last().first + 1
68+
val newYearInLastOffset = LocalDate(firstYearWithRecurringRules, Month.JANUARY, 1).atTime(0, 0)
69+
.toInstant(lastOffset)
70+
transitionEpochSeconds.add(newYearInLastOffset.epochSeconds)
71+
}
72+
offsets.add(recurring.offsetAtYearStart())
6473
TimeZoneRules(transitionEpochSeconds, offsets, recurringRules)
6574
}
6675
put(name, rules)

core/windows/test/TimeZoneRulesCompleteTest.kt

+36-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
package kotlinx.datetime.test
88

99
import kotlinx.cinterop.*
10+
import kotlinx.cinterop.ptr
1011
import kotlinx.datetime.*
1112
import kotlinx.datetime.internal.*
1213
import platform.windows.*
@@ -16,6 +17,7 @@ import kotlin.time.Duration.Companion.milliseconds
1617
class TimeZoneRulesCompleteTest {
1718

1819
/** Tests that all transitions that our system recognizes are actually there. */
20+
@OptIn(ExperimentalStdlibApi::class)
1921
@Test
2022
fun iterateOverAllTimezones() {
2123
val tzdb = TzdbInRegistry()
@@ -42,7 +44,38 @@ class TimeZoneRulesCompleteTest {
4244
val ldt = instant.toLocalDateTime(dtzi, inputSystemtime.ptr, outputSystemtime.ptr)
4345
val offset = rules.infoAtInstant(instant)
4446
val ourLdt = instant.toLocalDateTime(offset)
45-
assertEquals(ldt, ourLdt, "in zone $windowsName, at $instant (our guess at the offset is $offset)")
47+
if (ldt != ourLdt) {
48+
val offsetsAccordingToWindows = buildList {
49+
var date = LocalDate(ldt.year, Month.JANUARY, 1)
50+
while (date.year == ldt.year) {
51+
val instant = date.atTime(0, 0).toInstant(UtcOffset.ZERO)
52+
val ldtAccordingToWindows =
53+
instant.toLocalDateTime(dtzi, inputSystemtime.ptr, outputSystemtime.ptr)
54+
val offsetAccordingToWindows =
55+
(ldtAccordingToWindows.toInstant(UtcOffset.ZERO) - instant).inWholeSeconds
56+
add(date to offsetAccordingToWindows)
57+
date = date.plus(1, DateTimeUnit.DAY)
58+
}
59+
}
60+
val rawData = memScoped {
61+
val hKey = alloc<HKEYVar>()
62+
RegOpenKeyExW(HKEY_LOCAL_MACHINE!!, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\$windowsName", 0u, KEY_READ.toUInt(), hKey.ptr)
63+
try {
64+
val cbDataBuffer = alloc<DWORDVar>()
65+
val SIZE_BYTES = 44
66+
val zoneInfoBuffer = allocArray<BYTEVar>(SIZE_BYTES)
67+
cbDataBuffer.value = SIZE_BYTES.convert()
68+
RegQueryValueExW(hKey.value, "TZI", null, null, zoneInfoBuffer, cbDataBuffer.ptr)
69+
zoneInfoBuffer.readBytes(SIZE_BYTES).toHexString()
70+
} finally {
71+
RegCloseKey(hKey.value)
72+
}
73+
}
74+
throw AssertionError(
75+
"Expected $ldt, got $ourLdt in zone $windowsName at $instant (our guess at the offset is $offset)." +
76+
"The rules are $rules, and the offsets throughout the year according to Windows are: $offsetsAccordingToWindows; the raw data for the recurring rules is $rawData"
77+
)
78+
}
4679
}
4780
fun checkTransition(instant: Instant) {
4881
checkAtInstant(instant - 2.milliseconds)
@@ -120,5 +153,6 @@ private fun SYSTEMTIME.toLocalDateTime(): LocalDateTime =
120153
)
121154

122155
private val strangeTimeZones = listOf(
123-
"Morocco Standard Time", "West Bank Standard Time", "Iran Standard Time", "Syria Standard Time"
156+
"Morocco Standard Time", "West Bank Standard Time", "Iran Standard Time", "Syria Standard Time",
157+
"Paraguay Standard Time"
124158
)

0 commit comments

Comments
 (0)