Skip to content

Commit 79732eb

Browse files
committed
Rewrite the Windows code in pure Kotlin
1 parent 0d14fdc commit 79732eb

17 files changed

+928
-1726
lines changed

.gitmodules

-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +0,0 @@
1-
[submodule "date-cpp-library/date"]
2-
path = thirdparty/date
3-
url = https://github.com/HowardHinnant/date

README.md

-9
Original file line numberDiff line numberDiff line change
@@ -381,15 +381,6 @@ Add a dependency to the `<dependencies>` element. Note that you need to use the
381381

382382
## Building
383383

384-
Before building, ensure that you have [thirdparty/date](thirdparty/date) submodule initialized and updated.
385-
IDEA does that automatically when cloning the repository, and if you cloned it in the command line, you may need
386-
to run additionally:
387-
388-
```kotlin
389-
git submodule init
390-
git submodule update
391-
```
392-
393384
The project requires JDK 8 to build classes and to run tests.
394385
Gradle will try to find it among the installed JDKs or [provision](https://docs.gradle.org/current/userguide/toolchains.html#sec:provisioning) it automatically if it couldn't be found.
395386
The path to JDK 8 can be additionally specified with the environment variable `JDK_8`.

core/build.gradle.kts

+17-36
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,9 @@ kotlin {
7474
}
7575
}
7676
// Tier 3
77-
target("mingwX64")
77+
common("windows") {
78+
target("mingwX64")
79+
}
7880
}
7981

8082
jvm {
@@ -143,24 +145,11 @@ kotlin {
143145
when {
144146
konanTarget.family == org.jetbrains.kotlin.konan.target.Family.MINGW -> {
145147
compilations["main"].cinterops {
146-
create("date") {
147-
val cinteropDir = "$projectDir/native/cinterop"
148-
val dateLibDir = "${project(":").projectDir}/thirdparty/date"
149-
headers("$cinteropDir/public/cdate.h")
150-
defFile("native/cinterop/date.def")
151-
extraOpts("-Xsource-compiler-option", "-I$cinteropDir/public")
152-
extraOpts("-Xsource-compiler-option", "-DONLY_C_LOCALE=1")
153-
// needed to be able to use std::shared_mutex to implement caching.
154-
extraOpts("-Xsource-compiler-option", "-std=c++17")
155-
// the date library headers, needed for some pure calculations.
156-
extraOpts("-Xsource-compiler-option", "-I$dateLibDir/include")
157-
// the main source for the platform bindings.
158-
extraOpts("-Xcompile-source", "$cinteropDir/cpp/windows.cpp")
148+
create("declarations") {
149+
defFile("$projectDir/windows/cinterop/definitions.def")
150+
headers("$projectDir/windows/cinterop/definitions.h")
159151
}
160152
}
161-
compilations["main"].defaultSourceSet {
162-
kotlin.srcDir("native/cinterop_actuals")
163-
}
164153
}
165154
konanTarget.family == org.jetbrains.kotlin.konan.target.Family.LINUX -> {
166155
// do nothing special
@@ -173,8 +162,6 @@ kotlin {
173162
}
174163
}
175164
}
176-
177-
178165
sourceSets {
179166
commonMain {
180167
dependencies {
@@ -321,10 +308,10 @@ tasks {
321308

322309
val downloadWindowsZonesMapping by tasks.registering {
323310
description = "Updates the mapping between Windows-specific and usual names for timezones"
324-
val output = "$projectDir/native/cinterop/public/windows_zones.hpp"
325-
val initialFileContents = File(output).readBytes()
311+
val output = "$projectDir/windows/src/WindowsZoneNames.kt"
326312
outputs.file(output)
327313
doLast {
314+
val initialFileContents = try { File(output).readBytes() } catch(e: Throwable) { ByteArray(0) }
328315
val documentBuilderFactory = DocumentBuilderFactory.newInstance()
329316
// otherwise, parsing fails since it can't find the dtd
330317
documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false)
@@ -336,11 +323,13 @@ val downloadWindowsZonesMapping by tasks.registering {
336323
xmlDoc.documentElement.normalize()
337324
val mapZones = xmlDoc.getElementsByTagName("mapZone")
338325
val mapping = linkedMapOf<String, String>()
326+
mapping["UTC"] = "UTC"
339327
for (i in 0 until mapZones.length) {
340328
val mapZone = mapZones.item(i)
341329
val windowsName = mapZone.attributes.getNamedItem("other").nodeValue
342330
val usualNames = mapZone.attributes.getNamedItem("type").nodeValue
343331
for (usualName in usualNames.split(' ')) {
332+
if (usualName == "") continue
344333
val oldWindowsName = mapping[usualName] // don't do it in `put` to preserve the order in the map
345334
if (oldWindowsName == null) {
346335
mapping[usualName] = windowsName
@@ -353,31 +342,23 @@ val downloadWindowsZonesMapping by tasks.registering {
353342
val bos = ByteArrayOutputStream()
354343
PrintWriter(bos).use { out ->
355344
out.println("""// generated with gradle task `$name`""")
356-
out.println("""#include <unordered_map>""")
357-
out.println("""#include <string>""")
358-
out.println("""static const std::unordered_map<std::string, std::string> standard_to_windows = {""")
345+
out.println("""package kotlinx.datetime""")
346+
out.println("""internal val standardToWindows: Map<String, String> = mutableMapOf(""")
359347
for ((usualName, windowsName) in sortedMapping) {
360-
out.println("\t{ \"$usualName\", \"$windowsName\" },")
348+
out.println(" \"$usualName\" to \"$windowsName\",")
361349
}
362-
out.println("};")
363-
out.println("""static const std::unordered_map<std::string, std::string> windows_to_standard = {""")
350+
out.println(")")
351+
out.println("""internal val windowsToStandard: Map<String, String> = mutableMapOf(""")
364352
val reverseMap = sortedMapOf<String, String>()
365353
for ((usualName, windowsName) in mapping) {
366354
if (reverseMap[windowsName] == null) {
367355
reverseMap[windowsName] = usualName
368356
}
369357
}
370358
for ((windowsName, usualName) in reverseMap) {
371-
out.println("\t{ \"$windowsName\", \"$usualName\" },")
372-
}
373-
out.println("};")
374-
out.println("""static const std::unordered_map<std::string, size_t> zone_ids = {""")
375-
var i = 0
376-
for ((usualName, windowsName) in sortedMapping) {
377-
out.println("\t{ \"$usualName\", $i },")
378-
++i
359+
out.println(" \"$windowsName\" to \"$usualName\",")
379360
}
380-
out.println("};")
361+
out.println(")")
381362
}
382363
val newFileContents = bos.toByteArray()
383364
if (!(initialFileContents contentEquals newFileContents)) {

core/common/test/TimeZoneTest.kt

+6-6
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@ class TimeZoneTest {
3535
@Test
3636
fun available() {
3737
val allTzIds = TimeZone.availableZoneIds
38-
assertContains(allTzIds, "Europe/Berlin")
39-
assertContains(allTzIds, "Europe/Moscow")
40-
assertContains(allTzIds, "America/New_York")
38+
assertContains(allTzIds, "Europe/Berlin", "Europe/Berlin not in $allTzIds")
39+
assertContains(allTzIds, "Europe/Moscow", "Europe/Moscow not in $allTzIds")
40+
assertContains(allTzIds, "America/New_York", "America/New_York not in $allTzIds")
4141

42-
assertNotEquals(0, allTzIds.size)
43-
assertTrue(TimeZone.currentSystemDefault().id in allTzIds)
44-
assertTrue("UTC" in allTzIds)
42+
assertTrue(TimeZone.currentSystemDefault().id in allTzIds,
43+
"The current system timezone ${TimeZone.currentSystemDefault().id} is not in $allTzIds")
44+
assertTrue("UTC" in allTzIds, "The UTC timezone not in $allTzIds")
4545
}
4646

4747
@Test

core/linux/test/TimeZoneRulesCompleteTest.kt

-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ fun parseRfc2822(input: String): Pair<LocalDateTime, String> {
113113
val abbreviation = input.substringAfterLast(" ")
114114
val dateTime = input.substringBeforeLast(" ")
115115
val components = dateTime.split(Regex(" +"))
116-
val dayOfWeek = components[0]
117116
val month = components[1]
118117
val dayOfMonth = components[2].toInt()
119118
val time = LocalTime.parse(components[3])

0 commit comments

Comments
 (0)