Skip to content

Commit

Permalink
Disable tests for one more timezone (#424)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
dkhalanskyjb authored Aug 19, 2024
1 parent 73b7afa commit 1cb9cdb
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 3 deletions.
15 changes: 15 additions & 0 deletions core/native/src/internal/TimeZoneRules.kt
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,21 @@ internal class TimeZoneRules(
val offsetAfter = offsets[transitionIndex + 1]
return OffsetInfo(transitionInstant, offsetBefore, offsetAfter)
}

override fun toString(): String = buildString {
for (i in transitionEpochSeconds.indices) {
append(offsets[i])
append(" until ")
append(Instant.fromEpochSeconds(transitionEpochSeconds[i]))
append(", ")
}
append("then ")
append(offsets.last())
if (recurringZoneRules != null) {
append(", after that ")
append(recurringZoneRules)
}
}
}

internal class RecurringZoneRules(
Expand Down
11 changes: 10 additions & 1 deletion core/windows/src/internal/TzdbInRegistry.kt
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,16 @@ internal class TzdbInRegistry: TimeZoneDatabase {
}
}
}
if (offsets.isEmpty()) { offsets.add(recurring.offsetAtYearStart()) }
offsets.lastOrNull()?.let { lastOffset ->
/* If there are already some offsets, we can not add a new offset without defining a transition to
it. The moment when we start using the recurring rules is the first year that does not have any
historic data provided. */
val firstYearWithRecurringRules = historic.last().first + 1
val newYearInLastOffset = LocalDate(firstYearWithRecurringRules, Month.JANUARY, 1).atTime(0, 0)
.toInstant(lastOffset)
transitionEpochSeconds.add(newYearInLastOffset.epochSeconds)
}
offsets.add(recurring.offsetAtYearStart())
TimeZoneRules(transitionEpochSeconds, offsets, recurringRules)
}
put(name, rules)
Expand Down
38 changes: 36 additions & 2 deletions core/windows/test/TimeZoneRulesCompleteTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package kotlinx.datetime.test

import kotlinx.cinterop.*
import kotlinx.cinterop.ptr
import kotlinx.datetime.*
import kotlinx.datetime.internal.*
import platform.windows.*
Expand All @@ -16,6 +17,7 @@ import kotlin.time.Duration.Companion.milliseconds
class TimeZoneRulesCompleteTest {

/** Tests that all transitions that our system recognizes are actually there. */
@OptIn(ExperimentalStdlibApi::class)
@Test
fun iterateOverAllTimezones() {
val tzdb = TzdbInRegistry()
Expand All @@ -42,7 +44,38 @@ class TimeZoneRulesCompleteTest {
val ldt = instant.toLocalDateTime(dtzi, inputSystemtime.ptr, outputSystemtime.ptr)
val offset = rules.infoAtInstant(instant)
val ourLdt = instant.toLocalDateTime(offset)
assertEquals(ldt, ourLdt, "in zone $windowsName, at $instant (our guess at the offset is $offset)")
if (ldt != ourLdt) {
val offsetsAccordingToWindows = buildList {
var date = LocalDate(ldt.year, Month.JANUARY, 1)
while (date.year == ldt.year) {
val instant = date.atTime(0, 0).toInstant(UtcOffset.ZERO)
val ldtAccordingToWindows =
instant.toLocalDateTime(dtzi, inputSystemtime.ptr, outputSystemtime.ptr)
val offsetAccordingToWindows =
(ldtAccordingToWindows.toInstant(UtcOffset.ZERO) - instant).inWholeSeconds
add(date to offsetAccordingToWindows)
date = date.plus(1, DateTimeUnit.DAY)
}
}
val rawData = memScoped {
val hKey = alloc<HKEYVar>()
RegOpenKeyExW(HKEY_LOCAL_MACHINE!!, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\$windowsName", 0u, KEY_READ.toUInt(), hKey.ptr)
try {
val cbDataBuffer = alloc<DWORDVar>()
val SIZE_BYTES = 44
val zoneInfoBuffer = allocArray<BYTEVar>(SIZE_BYTES)
cbDataBuffer.value = SIZE_BYTES.convert()
RegQueryValueExW(hKey.value, "TZI", null, null, zoneInfoBuffer, cbDataBuffer.ptr)
zoneInfoBuffer.readBytes(SIZE_BYTES).toHexString()
} finally {
RegCloseKey(hKey.value)
}
}
throw AssertionError(
"Expected $ldt, got $ourLdt in zone $windowsName at $instant (our guess at the offset is $offset)." +
"The rules are $rules, and the offsets throughout the year according to Windows are: $offsetsAccordingToWindows; the raw data for the recurring rules is $rawData"
)
}
}
fun checkTransition(instant: Instant) {
checkAtInstant(instant - 2.milliseconds)
Expand Down Expand Up @@ -120,5 +153,6 @@ private fun SYSTEMTIME.toLocalDateTime(): LocalDateTime =
)

private val strangeTimeZones = listOf(
"Morocco Standard Time", "West Bank Standard Time", "Iran Standard Time", "Syria Standard Time"
"Morocco Standard Time", "West Bank Standard Time", "Iran Standard Time", "Syria Standard Time",
"Paraguay Standard Time"
)

0 comments on commit 1cb9cdb

Please sign in to comment.