Skip to content

Commit e1a2c61

Browse files
committed
Cleanup
1 parent 17bfddc commit e1a2c61

File tree

11 files changed

+93
-69
lines changed

11 files changed

+93
-69
lines changed

core/common/src/DateTimePeriod.kt

+12-5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import kotlinx.datetime.serializers.DateTimePeriodComponentSerializer
1313
import kotlin.math.*
1414
import kotlin.time.Duration
1515
import kotlinx.serialization.Serializable
16+
import kotlin.text.toLong
1617

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

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

504510
private fun totalNanoseconds(hours: Int, minutes: Int, seconds: Int, nanoseconds: Long): Long {
505511
val totalMinutes: Long = hours.toLong() * 60 + minutes
@@ -536,9 +542,10 @@ internal fun buildDateTimePeriod(totalMonths: Long = 0, days: Int = 0, totalNano
536542
* (like "yearly" or "quarterly"), please consider using a multiple of [DateTimeUnit] instead.
537543
* For example, instead of `DateTimePeriod(months = 6)`, one can use `DateTimeUnit.MONTH * 6`.
538544
*
539-
* @throws IllegalArgumentException if the total number of months in [years] and [months] overflows an [Int].
540-
* @throws IllegalArgumentException if the total number of months in [hours], [minutes], [seconds] and [nanoseconds]
541-
* overflows a [Long].
545+
* @throws IllegalArgumentException if the total number of years
546+
* (together with full years in [months]) overflows an [Int].
547+
* @throws IllegalArgumentException if the total number of nanoseconds in
548+
* [hours], [minutes], [seconds] and [nanoseconds] overflows a [Long].
542549
* @sample kotlinx.datetime.test.samples.DateTimePeriodSamples.constructorFunction
543550
*/
544551
public fun DateTimePeriod(

core/common/test/DateTimePeriodTest.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ class DateTimePeriodTest {
114114

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

117-
// overflow of `Long.MAX_VALUE` months
117+
// overflow of `Int.MAX_VALUE` years
118118
assertFailsWith<IllegalArgumentException> { DateTimePeriod.parse("P768614336404564651Y") }
119119
assertFailsWith<IllegalArgumentException> { DateTimePeriod.parse("P1Y9223372036854775805M") }
120120

core/common/test/InstantTest.kt

+6-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import kotlinx.datetime.internal.*
1111
import kotlin.random.*
1212
import kotlin.test.*
1313
import kotlin.time.*
14+
import kotlin.time.Duration.Companion.days
1415
import kotlin.time.Duration.Companion.hours
1516
import kotlin.time.Duration.Companion.milliseconds
1617
import kotlin.time.Duration.Companion.nanoseconds
@@ -268,9 +269,8 @@ class InstantTest {
268269
val offset3 = instant3.offsetIn(zone)
269270
assertEquals(offset1, offset3)
270271

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

276276
@Test
@@ -313,7 +313,9 @@ class InstantTest {
313313
val diff2 = date1.periodUntil(date2)
314314

315315
if (diff1 != diff2)
316-
println("start: $instant1, end: $instant2, diff by instants: $diff1, diff by dates: $diff2")
316+
throw AssertionError(
317+
"start: $instant1, end: $instant2, diff by instants: $diff1, diff by dates: $diff2"
318+
)
317319
}
318320
}
319321
}

core/commonJs/src/PlatformSpecifics.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ public expect interface InteropInterface
1212

1313
@OptIn(ExperimentalMultiplatform::class)
1414
@Retention(AnnotationRetention.BINARY)
15-
@Target(AnnotationTarget.CLASS, AnnotationTarget.FILE)
15+
@Target(AnnotationTarget.FILE)
1616
@OptionalExpectation
1717
public expect annotation class JsNonModule()
1818

1919
@Retention(AnnotationRetention.BINARY)
20-
@Target(AnnotationTarget.CLASS, AnnotationTarget.FILE)
20+
@Target(AnnotationTarget.FILE)
2121
public expect annotation class JsModule(val import: String)

core/commonJs/src/internal/Platform.kt

-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ private val tzdb: Result<TimeZoneDatabase?> = runCatching {
7676
(unpackBase60(it) * SECONDS_PER_MINUTE * MILLIS_PER_ONE).roundToLong() / // minutes to milliseconds
7777
MILLIS_PER_ONE // but we only need seconds
7878
}
79-
println("Zone ${components[0]}: $offsets with ${components[2]} raw data")
8079
zones[components[0]] = TimeZoneRules(
8180
transitionEpochSeconds = lengthsOfPeriodsWithOffsets.partialSums().take<Long>(indices.size - 1),
8281
offsets = indices.map { UtcOffset(null, null, -(offsets[it] * 60).roundToInt()) },

core/commonJs/test/JsJodaTimezoneTest.kt

+27-23
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import kotlin.math.roundToInt
1010
import kotlin.test.*
1111
import kotlin.time.Duration.Companion.milliseconds
1212
import kotlin.time.Duration.Companion.seconds
13+
import kotlinx.datetime.test.JSJoda.Instant as jtInstant
14+
import kotlinx.datetime.test.JSJoda.ZoneId as jtZoneId
1315

1416
class JsJodaTimezoneTest {
1517
@Test
@@ -25,33 +27,35 @@ class JsJodaTimezoneTest {
2527
fun iterateOverAllTimezones() {
2628
for (id in TimeZone.availableZoneIds) {
2729
val rules = rulesForId(id) ?: throw AssertionError("No rules for $id")
28-
val jodaZone = kotlinx.datetime.test.JSJoda.ZoneId.of(id)
29-
assertNull(rules.recurringZoneRules)
30+
val jodaZone = jtZoneId.of(id)
31+
assertNull(rules.recurringZoneRules) // js-joda doesn't expose recurring rules
3032
fun checkAtInstant(instant: Instant) {
31-
val jodaInstant = kotlinx.datetime.test.JSJoda.Instant.ofEpochMilli(instant.toEpochMilliseconds().toDouble())
32-
val zdt = jodaInstant.atZone(jodaZone)
3333
val offset = rules.infoAtInstant(instant)
3434
val ourLdt = instant.toLocalDateTime(offset)
35-
val theirLdt = LocalDateTime(
36-
zdt.year(),
37-
zdt.monthValue(),
38-
zdt.dayOfMonth(),
39-
zdt.hour(),
40-
zdt.minute(),
41-
zdt.second(),
42-
zdt.nano().roundToInt()
43-
)
44-
if ((ourLdt.toInstant(TimeZone.UTC) - theirLdt.toInstant(TimeZone.UTC)).absoluteValue > 1.seconds) {
45-
// It seems that sometimes, js-joda interprets its data incorrectly by at most one second,
46-
// and we don't want to replicate that.
47-
// Example: America/Noronha at 1914-01-01T02:09:39.998Z:
48-
// - Computed 1913-12-31T23:59:59.998 with offset -02:09:40
49-
// - 1914-01-01T00:00:00.998-02:09:39[America/Noronha] is js-joda's interpretation
50-
// The raw data representing the offset is `29.E`, which is `2 * 60 + 9 + (ord 'E' - 29) / 60`,
51-
// and `ord 'E'` is 69, so the offset is -2:09:40.
52-
// Thus, we allow a difference of 1 second.
53-
throw AssertionError("Failed for $id at $instant: computed $ourLdt with offset $offset, but $zdt is correct")
35+
val zdt = jtInstant.ofEpochMilli(instant.toEpochMilliseconds().toDouble()).atZone(jodaZone)
36+
val theirLdt = with(zdt) {
37+
LocalDateTime(
38+
year(),
39+
monthValue(),
40+
dayOfMonth(),
41+
hour(),
42+
minute(),
43+
second(),
44+
nano().roundToInt()
45+
)
5446
}
47+
// It seems that sometimes, js-joda interprets its data incorrectly by at most one second,
48+
// and we don't want to replicate that.
49+
// Example: America/Noronha at 1914-01-01T02:09:39.998Z:
50+
// - Computed 1913-12-31T23:59:59.998 with offset -02:09:40
51+
// - 1914-01-01T00:00:00.998-02:09:39[America/Noronha] is js-joda's interpretation
52+
// The raw data representing the offset is `29.E`, which is `2 * 60 + 9 + (ord 'E' - 29) / 60`,
53+
// and `ord 'E'` is 69, so the offset is -2:09:40.
54+
// Thus, we allow a difference of 1 second.
55+
assertTrue(
56+
(ourLdt.toInstant(TimeZone.UTC) - theirLdt.toInstant(TimeZone.UTC)).absoluteValue <= 1.seconds,
57+
"Failed for $id at $instant: computed $ourLdt with offset $offset, but $zdt is correct"
58+
)
5559
}
5660
fun checkTransition(instant: Instant) {
5761
checkAtInstant(instant - 2.milliseconds)

core/commonKotlin/src/Instant.kt

+4-4
Original file line numberDiff line numberDiff line change
@@ -242,12 +242,12 @@ public actual fun Instant.periodUntil(other: Instant, timeZone: TimeZone): DateT
242242
val otherLdt = other.toZonedDateTimeFailing(timeZone)
243243

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

250-
return buildDateTimePeriod(months, days, nanoseconds)
250+
return buildDateTimePeriod(months, days.toInt(), nanoseconds)
251251
}
252252

253253
public actual fun Instant.until(other: Instant, unit: DateTimeUnit, timeZone: TimeZone): Long =

core/commonKotlin/src/internal/Platform.kt

-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ package kotlinx.datetime.internal
88
import kotlinx.datetime.Instant
99
import kotlinx.datetime.TimeZone
1010

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

1413
internal expect fun getAvailableZoneIds(): Set<String>

js-without-timezones/build.gradle.kts

-21
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,12 @@ plugins {
88
id("org.jetbrains.kotlinx.kover")
99
}
1010

11-
val mainJavaToolchainVersion: String by project
12-
13-
java {
14-
toolchain { languageVersion.set(JavaLanguageVersion.of(mainJavaToolchainVersion)) }
15-
}
16-
1711
kotlin {
18-
1912
js {
2013
nodejs {
2114
}
22-
compilations.all {
23-
kotlinOptions {
24-
sourceMap = true
25-
moduleKind = "umd"
26-
metaInfo = true
27-
}
28-
}
2915
}
3016

31-
3217
wasmJs {
3318
nodejs {
3419
}
@@ -42,12 +27,6 @@ kotlin {
4227
resources.srcDir("$targetName/${suffix?.let { it + "Resources" } ?: "resources"}")
4328
}
4429

45-
targets.withType<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget> {
46-
compilations["test"].kotlinOptions {
47-
freeCompilerArgs += listOf("-trw")
48-
}
49-
}
50-
5130
sourceSets {
5231
commonMain {
5332
dependencies {

license/README.md

+7-7
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,19 @@ may apply:
66
- Origin: implementation of date/time calculations is based on ThreeTen backport project.
77
- License: BSD 3-Clause ([license/thirdparty/threetenbp_license.txt][threetenbp])
88

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

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

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

21-
- Path: `thirdparty/date`
22-
- Origin: https://github.com/HowardHinnant/date library
23-
- License: MIT ([license/thirdparty/cppdate_license.txt](thirdparty/cppdate_license.txt))
24-
25-
- Path: `core/nativeMain/cinterop/public/windows_zones.hpp`
21+
- Path: `core/windows/src/internal/WindowsZoneNames.kt`
2622
- Origin: time zone name mappings for Windows are generated from
2723
https://raw.githubusercontent.com/unicode-org/cldr/master/common/supplemental/windowsZones.xml
2824
- License: Unicode ([license/thirdparty/unicode_license.txt](thirdparty/unicode_license.txt))
@@ -31,4 +27,8 @@ may apply:
3127
- Origin: implementation is based on the bionic project.
3228
- License: BSD ([license/thirdparty/bionic_license.txt](thirdparty/bionic_license.txt))
3329

30+
- Path: `core/commonJs/src`
31+
- Origin: implementation accesses the internals of js-joda.
32+
- License: BSD ([license/thirdparty/js-joda_license.txt](thirdparty/js-joda_license.txt))
33+
3434
[threetenbp]: thirdparty/threetenbp_license.txt
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
BSD License
2+
3+
For js-joda software
4+
5+
Copyright (c) 2016, Philipp Thürwächter & Pattrick Hüper
6+
7+
All rights reserved.
8+
9+
Redistribution and use in source and binary forms, with or without
10+
modification, are permitted provided that the following conditions are met:
11+
12+
* Redistributions of source code must retain the above copyright notice,
13+
this list of conditions and the following disclaimer.
14+
15+
* Redistributions in binary form must reproduce the above copyright notice,
16+
this list of conditions and the following disclaimer in the documentation
17+
and/or other materials provided with the distribution.
18+
19+
* Neither the name of js-joda nor the names of its contributors
20+
may be used to endorse or promote products derived from this software
21+
without specific prior written permission.
22+
23+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
27+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34+

0 commit comments

Comments
 (0)