Skip to content

Commit

Permalink
Cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
dkhalanskyjb committed Nov 5, 2024
1 parent 17bfddc commit ae4373e
Show file tree
Hide file tree
Showing 10 changed files with 59 additions and 69 deletions.
17 changes: 12 additions & 5 deletions core/common/src/DateTimePeriod.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import kotlinx.datetime.serializers.DateTimePeriodComponentSerializer
import kotlin.math.*
import kotlin.time.Duration
import kotlinx.serialization.Serializable
import kotlin.text.toLong

/**
* A difference between two [instants][Instant], decomposed into date and time components.
Expand Down Expand Up @@ -448,7 +449,8 @@ public class DatePeriod internal constructor(
* (like "yearly" or "quarterly"), please consider using a multiple of [DateTimeUnit.DateBased] instead.
* For example, instead of `DatePeriod(months = 6)`, one can use `DateTimeUnit.MONTH * 6`.
*
* @throws IllegalArgumentException if the total number of months in [years] and [months] overflows an [Int].
* @throws IllegalArgumentException if the total number of years
* (together with full years in [months]) overflows an [Int].
* @sample kotlinx.datetime.test.samples.DatePeriodSamples.construction
*/
public constructor(years: Int = 0, months: Int = 0, days: Int = 0): this(totalMonths(years, months), days)
Expand Down Expand Up @@ -499,7 +501,11 @@ private class DateTimePeriodImpl(
override val totalNanoseconds: Long,
) : DateTimePeriod()

private fun totalMonths(years: Int, months: Int): Long = years.toLong() * 12 + months.toLong()
private fun totalMonths(years: Int, months: Int): Long = (years.toLong() * 12 + months.toLong()).also {
require(it / 12 in Int.MIN_VALUE..Int.MAX_VALUE) {
"The total number of years in $years years and $months months overflows an Int"
}
}

private fun totalNanoseconds(hours: Int, minutes: Int, seconds: Int, nanoseconds: Long): Long {
val totalMinutes: Long = hours.toLong() * 60 + minutes
Expand Down Expand Up @@ -536,9 +542,10 @@ internal fun buildDateTimePeriod(totalMonths: Long = 0, days: Int = 0, totalNano
* (like "yearly" or "quarterly"), please consider using a multiple of [DateTimeUnit] instead.
* For example, instead of `DateTimePeriod(months = 6)`, one can use `DateTimeUnit.MONTH * 6`.
*
* @throws IllegalArgumentException if the total number of months in [years] and [months] overflows an [Int].
* @throws IllegalArgumentException if the total number of months in [hours], [minutes], [seconds] and [nanoseconds]
* overflows a [Long].
* @throws IllegalArgumentException if the total number of years
* (together with full years in [months]) overflows an [Int].
* @throws IllegalArgumentException if the total number of nanoseconds in
* [hours], [minutes], [seconds] and [nanoseconds] overflows a [Long].
* @sample kotlinx.datetime.test.samples.DateTimePeriodSamples.constructorFunction
*/
public fun DateTimePeriod(
Expand Down
2 changes: 1 addition & 1 deletion core/common/test/DateTimePeriodTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ class DateTimePeriodTest {

assertFailsWith<IllegalArgumentException> { DateTimePeriod.parse("P") }

// overflow of `Long.MAX_VALUE` months
// overflow of `Int.MAX_VALUE` years
assertFailsWith<IllegalArgumentException> { DateTimePeriod.parse("P768614336404564651Y") }
assertFailsWith<IllegalArgumentException> { DateTimePeriod.parse("P1Y9223372036854775805M") }

Expand Down
10 changes: 6 additions & 4 deletions core/common/test/InstantTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import kotlinx.datetime.internal.*
import kotlin.random.*
import kotlin.test.*
import kotlin.time.*
import kotlin.time.Duration.Companion.days
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.nanoseconds
Expand Down Expand Up @@ -268,9 +269,8 @@ class InstantTest {
val offset3 = instant3.offsetIn(zone)
assertEquals(offset1, offset3)

// TODO: fails on JS
// // without the minus, this test fails on JVM
// (Instant.MAX - (2 * 365).days).offsetIn(zone)
// without the minus, this test fails on JVM
(Instant.MAX - (2 * 365).days).offsetIn(zone)
}

@Test
Expand Down Expand Up @@ -313,7 +313,9 @@ class InstantTest {
val diff2 = date1.periodUntil(date2)

if (diff1 != diff2)
println("start: $instant1, end: $instant2, diff by instants: $diff1, diff by dates: $diff2")
throw AssertionError(
"start: $instant1, end: $instant2, diff by instants: $diff1, diff by dates: $diff2"
)
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions core/commonJs/src/PlatformSpecifics.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ public expect interface InteropInterface

@OptIn(ExperimentalMultiplatform::class)
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FILE)
@Target(AnnotationTarget.FILE)
@OptionalExpectation
public expect annotation class JsNonModule()

@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FILE)
@Target(AnnotationTarget.FILE)
public expect annotation class JsModule(val import: String)
1 change: 0 additions & 1 deletion core/commonJs/src/internal/Platform.kt
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ private val tzdb: Result<TimeZoneDatabase?> = runCatching {
(unpackBase60(it) * SECONDS_PER_MINUTE * MILLIS_PER_ONE).roundToLong() / // minutes to milliseconds
MILLIS_PER_ONE // but we only need seconds
}
println("Zone ${components[0]}: $offsets with ${components[2]} raw data")
zones[components[0]] = TimeZoneRules(
transitionEpochSeconds = lengthsOfPeriodsWithOffsets.partialSums().take<Long>(indices.size - 1),
offsets = indices.map { UtcOffset(null, null, -(offsets[it] * 60).roundToInt()) },
Expand Down
50 changes: 27 additions & 23 deletions core/commonJs/test/JsJodaTimezoneTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import kotlin.math.roundToInt
import kotlin.test.*
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds
import kotlinx.datetime.test.JSJoda.Instant as jtInstant
import kotlinx.datetime.test.JSJoda.ZoneId as jtZoneId

class JsJodaTimezoneTest {
@Test
Expand All @@ -25,33 +27,35 @@ class JsJodaTimezoneTest {
fun iterateOverAllTimezones() {
for (id in TimeZone.availableZoneIds) {
val rules = rulesForId(id) ?: throw AssertionError("No rules for $id")
val jodaZone = kotlinx.datetime.test.JSJoda.ZoneId.of(id)
assertNull(rules.recurringZoneRules)
val jodaZone = jtZoneId.of(id)
assertNull(rules.recurringZoneRules) // js-joda doesn't expose recurring rules
fun checkAtInstant(instant: Instant) {
val jodaInstant = kotlinx.datetime.test.JSJoda.Instant.ofEpochMilli(instant.toEpochMilliseconds().toDouble())
val zdt = jodaInstant.atZone(jodaZone)
val offset = rules.infoAtInstant(instant)
val ourLdt = instant.toLocalDateTime(offset)
val theirLdt = LocalDateTime(
zdt.year(),
zdt.monthValue(),
zdt.dayOfMonth(),
zdt.hour(),
zdt.minute(),
zdt.second(),
zdt.nano().roundToInt()
)
if ((ourLdt.toInstant(TimeZone.UTC) - theirLdt.toInstant(TimeZone.UTC)).absoluteValue > 1.seconds) {
// It seems that sometimes, js-joda interprets its data incorrectly by at most one second,
// and we don't want to replicate that.
// Example: America/Noronha at 1914-01-01T02:09:39.998Z:
// - Computed 1913-12-31T23:59:59.998 with offset -02:09:40
// - 1914-01-01T00:00:00.998-02:09:39[America/Noronha] is js-joda's interpretation
// The raw data representing the offset is `29.E`, which is `2 * 60 + 9 + (ord 'E' - 29) / 60`,
// and `ord 'E'` is 69, so the offset is -2:09:40.
// Thus, we allow a difference of 1 second.
throw AssertionError("Failed for $id at $instant: computed $ourLdt with offset $offset, but $zdt is correct")
val zdt = jtInstant.ofEpochMilli(instant.toEpochMilliseconds().toDouble()).atZone(jodaZone)
val theirLdt = with(zdt) {
LocalDateTime(
year(),
monthValue(),
dayOfMonth(),
hour(),
minute(),
second(),
nano().roundToInt()
)
}
// It seems that sometimes, js-joda interprets its data incorrectly by at most one second,
// and we don't want to replicate that.
// Example: America/Noronha at 1914-01-01T02:09:39.998Z:
// - Computed 1913-12-31T23:59:59.998 with offset -02:09:40
// - 1914-01-01T00:00:00.998-02:09:39[America/Noronha] is js-joda's interpretation
// The raw data representing the offset is `29.E`, which is `2 * 60 + 9 + (ord 'E' - 29) / 60`,
// and `ord 'E'` is 69, so the offset is -2:09:40.
// Thus, we allow a difference of 1 second.
assertTrue(
(ourLdt.toInstant(TimeZone.UTC) - theirLdt.toInstant(TimeZone.UTC)).absoluteValue <= 1.seconds,
"Failed for $id at $instant: computed $ourLdt with offset $offset, but $zdt is correct"
)
}
fun checkTransition(instant: Instant) {
checkAtInstant(instant - 2.milliseconds)
Expand Down
8 changes: 4 additions & 4 deletions core/commonKotlin/src/Instant.kt
Original file line number Diff line number Diff line change
Expand Up @@ -242,12 +242,12 @@ public actual fun Instant.periodUntil(other: Instant, timeZone: TimeZone): DateT
val otherLdt = other.toZonedDateTimeFailing(timeZone)

val months = thisLdt.until(otherLdt, DateTimeUnit.MONTH) // `until` on dates never fails
thisLdt = thisLdt.plus(months.toLong(), DateTimeUnit.MONTH) // won't throw: thisLdt + months <= otherLdt, which is known to be valid
val days = thisLdt.until(otherLdt, DateTimeUnit.DAY).toInt() // `until` on dates never fails
thisLdt = thisLdt.plus(days.toLong(), DateTimeUnit.DAY) // won't throw: thisLdt + days <= otherLdt
thisLdt = thisLdt.plus(months, DateTimeUnit.MONTH) // won't throw: thisLdt + months <= otherLdt, which is known to be valid
val days = thisLdt.until(otherLdt, DateTimeUnit.DAY) // `until` on dates never fails
thisLdt = thisLdt.plus(days, DateTimeUnit.DAY) // won't throw: thisLdt + days <= otherLdt
val nanoseconds = thisLdt.until(otherLdt, DateTimeUnit.NANOSECOND) // |otherLdt - thisLdt| < 24h

return buildDateTimePeriod(months, days, nanoseconds)
return buildDateTimePeriod(months, days.toInt(), nanoseconds)
}

public actual fun Instant.until(other: Instant, unit: DateTimeUnit, timeZone: TimeZone): Long =
Expand Down
1 change: 0 additions & 1 deletion core/commonKotlin/src/internal/Platform.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ package kotlinx.datetime.internal
import kotlinx.datetime.Instant
import kotlinx.datetime.TimeZone

// RegionTimeZone(systemTzdb.rulesForId(zoneId), zoneId)
internal expect fun timeZoneById(zoneId: String): TimeZone

internal expect fun getAvailableZoneIds(): Set<String>
Expand Down
21 changes: 0 additions & 21 deletions js-without-timezones/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,12 @@ plugins {
id("org.jetbrains.kotlinx.kover")
}

val mainJavaToolchainVersion: String by project

java {
toolchain { languageVersion.set(JavaLanguageVersion.of(mainJavaToolchainVersion)) }
}

kotlin {

js {
nodejs {
}
compilations.all {
kotlinOptions {
sourceMap = true
moduleKind = "umd"
metaInfo = true
}
}
}


wasmJs {
nodejs {
}
Expand All @@ -42,12 +27,6 @@ kotlin {
resources.srcDir("$targetName/${suffix?.let { it + "Resources" } ?: "resources"}")
}

targets.withType<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget> {
compilations["test"].kotlinOptions {
freeCompilerArgs += listOf("-trw")
}
}

sourceSets {
commonMain {
dependencies {
Expand Down
14 changes: 7 additions & 7 deletions license/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,19 @@ may apply:
- Origin: implementation of date/time calculations is based on ThreeTen backport project.
- License: BSD 3-Clause ([license/thirdparty/threetenbp_license.txt][threetenbp])

- Path: `core/nativeMain/src`
- Path: `core/commonKotlin/src`
- Origin: implementation of date/time entities is based on ThreeTen backport project.
- License: BSD 3-Clause ([license/thirdparty/threetenbp_license.txt][threetenbp])

- Path: `core/nativeTest/src`
- Path: `core/commonKotlin/src`
- Origin: Derived from tests of ThreeTen backport project
- License: BSD 3-Clause ([license/thirdparty/threetenbp_license.txt][threetenbp])

- Path: `core/commonTest/src`
- Origin: Some tests are derived from tests of ThreeTen backport project
- License: BSD 3-Clause ([license/thirdparty/threetenbp_license.txt][threetenbp])

- Path: `thirdparty/date`
- Origin: https://github.com/HowardHinnant/date library
- License: MIT ([license/thirdparty/cppdate_license.txt](thirdparty/cppdate_license.txt))

- Path: `core/nativeMain/cinterop/public/windows_zones.hpp`
- Path: `core/windows/src/internal/WindowsZoneNames.kt`
- Origin: time zone name mappings for Windows are generated from
https://raw.githubusercontent.com/unicode-org/cldr/master/common/supplemental/windowsZones.xml
- License: Unicode ([license/thirdparty/unicode_license.txt](thirdparty/unicode_license.txt))
Expand All @@ -31,4 +27,8 @@ may apply:
- Origin: implementation is based on the bionic project.
- License: BSD ([license/thirdparty/bionic_license.txt](thirdparty/bionic_license.txt))

- Path: `core/commonJs/src`
- Origin: implementation accesses the internals of js-joda.
- License: BSD ([license/thirdparty/js-joda_license.txt](thirdparty/js-joda_license.txt))

[threetenbp]: thirdparty/threetenbp_license.txt

0 comments on commit ae4373e

Please sign in to comment.