Dates and time zones¶
Two settings decide what Date does¶
KiteJs {
timeZone = TimeZone.of("Europe/Berlin")
clock = { 1_700_000_000_000.0 }
}.use { js ->
js.evaluate("new Date().toISOString()").asString() // 2023-11-14T22:13:20.000Z
js.evaluate("new Date(0).getHours()").asDouble() // 1.0
}
timeZone is the zone local time is read in. clock answers the current time in epoch
milliseconds. Both default to the system's, which is what you want in production and never what
you want in a test.
Pin the clock in tests¶
A script that reads the time gives a different answer every run. Fix the clock and it stops.
val fixed = 1_700_000_000_000.0
KiteJs { clock = { fixed }; timeZone = TimeZone.UTC }.use { js ->
assertEquals("2023-11-14", js.evaluate("new Date().toISOString().slice(0, 10)").asString())
}
A clock is a lambda, so it can move:
var now = 0.0
KiteJs { clock = { now } }.use { js ->
js.evaluate("var t0 = Date.now()")
now += 5000
js.evaluate("Date.now() - t0").asDouble() // 5000.0
}
The arithmetic is the engine's own¶
Leap years, month lengths, the day of the week, the ISO week, Date.UTC, Date.parse and every
getter and setter are computed inside the engine. They do not go through a platform date library,
so they give the same answer everywhere.
The one thing the engine cannot compute is which offset a zone used on a given day. Those rules change by political decision and have to come from a database. KiteJS reads them through kotlinx-datetime.
JavaScript and WebAssembly need one npm package¶
On those two targets the zone database is a separate npm package, @js-joda/timezone. KiteJS
declares it, so a normal Gradle build picks it up. Without it a named zone throws and only UTC
and fixed offsets work.
If you bundle the output yourself, make sure the package survives tree shaking. KiteJS holds an eager reference to it for exactly this reason.
Two gaps worth knowing¶
toString prints the zone's id where a browser prints its abbreviation:
KiteJS: Tue Nov 14 2023 23:13:20 GMT+0100 (Europe/Berlin)
Chrome: Tue Nov 14 2023 23:13:20 GMT+0100 (Central European Standard Time)
toLocaleString, toLocaleDateString and toLocaleTimeString use fixed en-US patterns and
ignore their locale argument. Formatting a date for a user is better done in Kotlin, where you
have the platform's formatter, than in the script.