Skip to content

Commit 7ae0691

Browse files
authored
Merge branch 'master' into master
2 parents 81e2e44 + 6d0de86 commit 7ae0691

15 files changed

+127
-85
lines changed

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
# CHANGELOG
22

3+
## 0.3.1
4+
5+
#### Fixes
6+
7+
- Fixed a crash in desugared code on Android when trying to construct time zones with some specific identifiers ([149](https://github.com/Kotlin/kotlinx-datetime/issues/149))
8+
9+
## 0.3.0
10+
11+
#### Features
12+
13+
- Added `iosSimulatorArm64`, `watchosSimulatorArm64`, `tvosSimulatorArm64`, `macosArm64` target support ([141](https://github.com/Kotlin/kotlinx-datetime/issues/141), [144](https://github.com/Kotlin/kotlinx-datetime/issues/144)).
14+
15+
#### Changes
16+
17+
- `ZoneOffset` was replaced by two other classes: `FixedOffsetTimeZone`, which represents a time zone with a fixed offset, and `UtcOffset`, which represents just the UTC offset ([PR#125](https://github.com/Kotlin/kotlinx-datetime/pull/125)).
18+
- The `DayBased` and `MonthBased` subclasses of `DateTimeUnit.DateBased` are now accessed as `DateTimeUnit.DayBased` and `DateTimeUnit.MonthBased` as opposed to `DateTimeUnit.DateBased.DayBased` and `DateTimeUnit.DateBased.MonthBased` respectively ([PR#131](https://github.com/Kotlin/kotlinx-datetime/pull/131)).
19+
320
## 0.2.1
421

522
#### Fixes

README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,14 @@ The library provides the basic set of types for working with date and time:
3636
- `Clock` to obtain the current instant;
3737
- `LocalDateTime` to represent date and time components without a reference to the particular time zone;
3838
- `LocalDate` to represent the components of date only;
39-
- `TimeZone` and `ZoneOffset` provide time zone information to convert between `Instant` and `LocalDateTime`;
39+
- `TimeZone` and `FixedOffsetTimeZone` provide time zone information to convert between `Instant` and `LocalDateTime`;
4040
- `Month` and `DayOfWeek` enums;
4141
- `DateTimePeriod` to represent a difference between two instants decomposed into date and time units;
4242
- `DatePeriod` is a subclass of `DateTimePeriod` with zero time components,
4343
it represents a difference between two LocalDate values decomposed into date units.
4444
- `DateTimeUnit` provides a set of predefined date and time units to use in arithmetic operations on `Instant` and `LocalDate`.
45-
45+
- `UtcOffset` represents the amount of time the local date/time at a particular time zone differs from the date/time at UTC.
46+
4647
### Type use-cases
4748

4849
Here is some basic advice on how to choose which of the date-carrying types to use in what cases:
@@ -295,7 +296,7 @@ kotlin {
295296
sourceSets {
296297
commonMain {
297298
dependencies {
298-
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.2.1")
299+
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.3.1")
299300
}
300301
}
301302
}
@@ -306,7 +307,7 @@ kotlin {
306307

307308
```groovy
308309
dependencies {
309-
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.2.1")
310+
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.3.1")
310311
}
311312
```
312313

@@ -346,7 +347,7 @@ Add a dependency to the `<dependencies>` element. Note that you need to use the
346347
<dependency>
347348
<groupId>org.jetbrains.kotlinx</groupId>
348349
<artifactId>kotlinx-datetime-jvm</artifactId>
349-
<version>0.2.1</version>
350+
<version>0.3.1</version>
350351
</dependency>
351352
```
352353

core/build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,19 @@ kotlin {
3131

3232
common("darwin") {
3333
target("macosX64")
34+
target("macosArm64")
3435
target("iosX64")
3536
target("iosArm64")
3637
target("iosArm32")
38+
target("iosSimulatorArm64")
3739
target("watchosArm32")
3840
target("watchosArm64")
3941
target("watchosX86")
4042
target("watchosX64")
43+
target("watchosSimulatorArm64")
4144
target("tvosArm64")
4245
target("tvosX64")
46+
target("tvosSimulatorArm64")
4347
}
4448
}
4549

core/common/src/DateTimeUnit.kt

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -66,44 +66,51 @@ public sealed class DateTimeUnit {
6666

6767
@Serializable(with = DateBasedDateTimeUnitSerializer::class)
6868
public sealed class DateBased : DateTimeUnit() {
69-
// TODO: investigate how to move subclasses up to DateTimeUnit scope
70-
@Serializable(with = DayBasedDateTimeUnitSerializer::class)
71-
public class DayBased(public val days: Int) : DateBased() {
72-
init {
73-
require(days > 0) { "Unit duration must be positive, but was $days days." }
74-
}
69+
@Suppress("TOPLEVEL_TYPEALIASES_ONLY")
70+
@Deprecated("Use DateTimeUnit.DayBased", ReplaceWith("DateTimeUnit.DayBased", "kotlinx.datetime.DateTimeUnit"))
71+
public typealias DayBased = DateTimeUnit.DayBased
72+
@Suppress("TOPLEVEL_TYPEALIASES_ONLY")
73+
@Deprecated("Use DateTimeUnit.MonthBased", ReplaceWith("DateTimeUnit.MonthBased", "kotlinx.datetime.DateTimeUnit"))
74+
public typealias MonthBased = DateTimeUnit.MonthBased
75+
}
76+
77+
@Serializable(with = DayBasedDateTimeUnitSerializer::class)
78+
public class DayBased(public val days: Int) : DateBased() {
79+
init {
80+
require(days > 0) { "Unit duration must be positive, but was $days days." }
81+
}
82+
83+
override fun times(scalar: Int): DateTimeUnit.DayBased = DateTimeUnit.DayBased(safeMultiply(days, scalar))
7584

76-
override fun times(scalar: Int): DayBased = DayBased(safeMultiply(days, scalar))
85+
override fun equals(other: Any?): Boolean =
86+
this === other || (other is DateTimeUnit.DayBased && this.days == other.days)
7787

78-
override fun equals(other: Any?): Boolean =
79-
this === other || (other is DayBased && this.days == other.days)
88+
override fun hashCode(): Int = days xor 0x10000
8089

81-
override fun hashCode(): Int = days xor 0x10000
90+
override fun toString(): String = if (days % 7 == 0)
91+
formatToString(days / 7, "WEEK")
92+
else
93+
formatToString(days, "DAY")
94+
}
8295

83-
override fun toString(): String = if (days % 7 == 0)
84-
formatToString(days / 7, "WEEK")
85-
else
86-
formatToString(days, "DAY")
96+
@Serializable(with = MonthBasedDateTimeUnitSerializer::class)
97+
public class MonthBased(public val months: Int) : DateBased() {
98+
init {
99+
require(months > 0) { "Unit duration must be positive, but was $months months." }
87100
}
88-
@Serializable(with = MonthBasedDateTimeUnitSerializer::class)
89-
public class MonthBased(public val months: Int) : DateBased() {
90-
init {
91-
require(months > 0) { "Unit duration must be positive, but was $months months." }
92-
}
93101

94-
override fun times(scalar: Int): MonthBased = MonthBased(safeMultiply(months, scalar))
102+
override fun times(scalar: Int): DateTimeUnit.MonthBased = DateTimeUnit.MonthBased(safeMultiply(months, scalar))
95103

96-
override fun equals(other: Any?): Boolean =
97-
this === other || (other is MonthBased && this.months == other.months)
104+
override fun equals(other: Any?): Boolean =
105+
this === other || (other is DateTimeUnit.MonthBased && this.months == other.months)
98106

99-
override fun hashCode(): Int = months xor 0x20000
107+
override fun hashCode(): Int = months xor 0x20000
100108

101-
override fun toString(): String = when {
102-
months % 12_00 == 0 -> formatToString(months / 12_00, "CENTURY")
103-
months % 12 == 0 -> formatToString(months / 12, "YEAR")
104-
months % 3 == 0 -> formatToString(months / 3, "QUARTER")
105-
else -> formatToString(months, "MONTH")
106-
}
109+
override fun toString(): String = when {
110+
months % 12_00 == 0 -> formatToString(months / 12_00, "CENTURY")
111+
months % 12 == 0 -> formatToString(months / 12, "YEAR")
112+
months % 3 == 0 -> formatToString(months / 3, "QUARTER")
113+
else -> formatToString(months, "MONTH")
107114
}
108115
}
109116

@@ -117,11 +124,11 @@ public sealed class DateTimeUnit {
117124
public val SECOND: TimeBased = MILLISECOND * 1000
118125
public val MINUTE: TimeBased = SECOND * 60
119126
public val HOUR: TimeBased = MINUTE * 60
120-
public val DAY: DateBased.DayBased = DateBased.DayBased(days = 1)
121-
public val WEEK: DateBased.DayBased = DAY * 7
122-
public val MONTH: DateBased.MonthBased = DateBased.MonthBased(months = 1)
123-
public val QUARTER: DateBased.MonthBased = MONTH * 3
124-
public val YEAR: DateBased.MonthBased = MONTH * 12
125-
public val CENTURY: DateBased.MonthBased = YEAR * 100
127+
public val DAY: DayBased = DayBased(days = 1)
128+
public val WEEK: DayBased = DAY * 7
129+
public val MONTH: MonthBased = MonthBased(months = 1)
130+
public val QUARTER: MonthBased = MONTH * 3
131+
public val YEAR: MonthBased = MONTH * 12
132+
public val CENTURY: MonthBased = YEAR * 100
126133
}
127134
}

core/common/src/serializers/DateTimeUnitSerializers.kt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,21 +53,21 @@ public object TimeBasedDateTimeUnitSerializer: KSerializer<DateTimeUnit.TimeBase
5353
}
5454
}
5555

56-
public object DayBasedDateTimeUnitSerializer: KSerializer<DateTimeUnit.DateBased.DayBased> {
56+
public object DayBasedDateTimeUnitSerializer: KSerializer<DateTimeUnit.DayBased> {
5757

5858
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("DayBased") {
5959
element<Int>("days")
6060
}
6161

62-
override fun serialize(encoder: Encoder, value: DateTimeUnit.DateBased.DayBased) {
62+
override fun serialize(encoder: Encoder, value: DateTimeUnit.DayBased) {
6363
encoder.encodeStructure(descriptor) {
6464
encodeIntElement(descriptor, 0, value.days)
6565
}
6666
}
6767

6868
@ExperimentalSerializationApi
6969
@Suppress("INVISIBLE_MEMBER") // to be able to throw `MissingFieldException`
70-
override fun deserialize(decoder: Decoder): DateTimeUnit.DateBased.DayBased {
70+
override fun deserialize(decoder: Decoder): DateTimeUnit.DayBased {
7171
var seen = false
7272
var days = 0
7373
decoder.decodeStructure(descriptor) {
@@ -88,25 +88,25 @@ public object DayBasedDateTimeUnitSerializer: KSerializer<DateTimeUnit.DateBased
8888
}
8989
}
9090
if (!seen) throw MissingFieldException("days")
91-
return DateTimeUnit.DateBased.DayBased(days)
91+
return DateTimeUnit.DayBased(days)
9292
}
9393
}
9494

95-
public object MonthBasedDateTimeUnitSerializer: KSerializer<DateTimeUnit.DateBased.MonthBased> {
95+
public object MonthBasedDateTimeUnitSerializer: KSerializer<DateTimeUnit.MonthBased> {
9696

9797
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("MonthBased") {
9898
element<Int>("months")
9999
}
100100

101-
override fun serialize(encoder: Encoder, value: DateTimeUnit.DateBased.MonthBased) {
101+
override fun serialize(encoder: Encoder, value: DateTimeUnit.MonthBased) {
102102
encoder.encodeStructure(descriptor) {
103103
encodeIntElement(descriptor, 0, value.months)
104104
}
105105
}
106106

107107
@ExperimentalSerializationApi
108108
@Suppress("INVISIBLE_MEMBER") // to be able to throw `MissingFieldException`
109-
override fun deserialize(decoder: Decoder): DateTimeUnit.DateBased.MonthBased {
109+
override fun deserialize(decoder: Decoder): DateTimeUnit.MonthBased {
110110
var seen = false
111111
var months = 0
112112
decoder.decodeStructure(descriptor) {
@@ -127,7 +127,7 @@ public object MonthBasedDateTimeUnitSerializer: KSerializer<DateTimeUnit.DateBas
127127
}
128128
}
129129
if (!seen) throw MissingFieldException("months")
130-
return DateTimeUnit.DateBased.MonthBased(months)
130+
return DateTimeUnit.MonthBased(months)
131131
}
132132
}
133133

@@ -136,7 +136,7 @@ public object DateBasedDateTimeUnitSerializer: AbstractPolymorphicSerializer<Dat
136136

137137
private val impl = SealedClassSerializer("kotlinx.datetime.DateTimeUnit.DateBased",
138138
DateTimeUnit.DateBased::class,
139-
arrayOf(DateTimeUnit.DateBased.DayBased::class, DateTimeUnit.DateBased.MonthBased::class),
139+
arrayOf(DateTimeUnit.DayBased::class, DateTimeUnit.MonthBased::class),
140140
arrayOf(DayBasedDateTimeUnitSerializer, MonthBasedDateTimeUnitSerializer))
141141

142142
@InternalSerializationApi
@@ -164,7 +164,7 @@ public object DateTimeUnitSerializer: AbstractPolymorphicSerializer<DateTimeUnit
164164

165165
private val impl = SealedClassSerializer("kotlinx.datetime.DateTimeUnit",
166166
DateTimeUnit::class,
167-
arrayOf(DateTimeUnit.DateBased.DayBased::class, DateTimeUnit.DateBased.MonthBased::class, DateTimeUnit.TimeBased::class),
167+
arrayOf(DateTimeUnit.DayBased::class, DateTimeUnit.MonthBased::class, DateTimeUnit.TimeBased::class),
168168
arrayOf(DayBasedDateTimeUnitSerializer, MonthBasedDateTimeUnitSerializer, TimeBasedDateTimeUnitSerializer))
169169

170170
@InternalSerializationApi

core/js/src/Instant.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,9 @@ public actual fun Instant.plus(value: Long, unit: DateTimeUnit, timeZone: TimeZo
145145
is DateTimeUnit.TimeBased -> {
146146
plus(value, unit).value.checkZone(timeZone)
147147
}
148-
is DateTimeUnit.DateBased.DayBased ->
148+
is DateTimeUnit.DayBased ->
149149
thisZdt.plusDays(value.toDouble() * unit.days).toInstant()
150-
is DateTimeUnit.DateBased.MonthBased ->
150+
is DateTimeUnit.MonthBased ->
151151
thisZdt.plusMonths(value.toDouble() * unit.months).toInstant()
152152
}.let(::Instant)
153153
} catch (e: Throwable) {
@@ -161,9 +161,9 @@ public actual fun Instant.plus(value: Int, unit: DateTimeUnit, timeZone: TimeZon
161161
when (unit) {
162162
is DateTimeUnit.TimeBased ->
163163
plus(value.toLong(), unit).value.checkZone(timeZone)
164-
is DateTimeUnit.DateBased.DayBased ->
164+
is DateTimeUnit.DayBased ->
165165
thisZdt.plusDays(value.toDouble() * unit.days).toInstant()
166-
is DateTimeUnit.DateBased.MonthBased ->
166+
is DateTimeUnit.MonthBased ->
167167
thisZdt.plusMonths(value.toDouble() * unit.months).toInstant()
168168
}.let(::Instant)
169169
} catch (e: Throwable) {
@@ -208,8 +208,8 @@ public actual fun Instant.until(other: Instant, unit: DateTimeUnit, timeZone: Ti
208208
val otherZdt = other.atZone(timeZone)
209209
when(unit) {
210210
is DateTimeUnit.TimeBased -> until(other, unit)
211-
is DateTimeUnit.DateBased.DayBased -> (thisZdt.until(otherZdt, ChronoUnit.DAYS).toDouble() / unit.days).toLong()
212-
is DateTimeUnit.DateBased.MonthBased -> (thisZdt.until(otherZdt, ChronoUnit.MONTHS).toDouble() / unit.months).toLong()
211+
is DateTimeUnit.DayBased -> (thisZdt.until(otherZdt, ChronoUnit.DAYS).toDouble() / unit.days).toLong()
212+
is DateTimeUnit.MonthBased -> (thisZdt.until(otherZdt, ChronoUnit.MONTHS).toDouble() / unit.months).toLong()
213213
}
214214
} catch (e: ArithmeticException) {
215215
if (this < other) Long.MAX_VALUE else Long.MIN_VALUE

core/js/src/LocalDate.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ public actual fun LocalDate.plus(value: Long, unit: DateTimeUnit.DateBased): Loc
5959
private fun LocalDate.plusNumber(value: Number, unit: DateTimeUnit.DateBased): LocalDate =
6060
try {
6161
when (unit) {
62-
is DateTimeUnit.DateBased.DayBased -> this.value.plusDays(value.toDouble() * unit.days)
63-
is DateTimeUnit.DateBased.MonthBased -> this.value.plusMonths(value.toDouble() * unit.months)
62+
is DateTimeUnit.DayBased -> this.value.plusDays(value.toDouble() * unit.days)
63+
is DateTimeUnit.MonthBased -> this.value.plusMonths(value.toDouble() * unit.months)
6464
}.let(::LocalDate)
6565
} catch (e: Throwable) {
6666
if (!e.isJodaDateTimeException() && !e.isJodaArithmeticException()) throw e
@@ -92,8 +92,8 @@ public actual fun LocalDate.periodUntil(other: LocalDate): DatePeriod {
9292
}
9393

9494
public actual fun LocalDate.until(other: LocalDate, unit: DateTimeUnit.DateBased): Int = when(unit) {
95-
is DateTimeUnit.DateBased.MonthBased -> monthsUntil(other) / unit.months
96-
is DateTimeUnit.DateBased.DayBased -> daysUntil(other) / unit.days
95+
is DateTimeUnit.MonthBased -> monthsUntil(other) / unit.months
96+
is DateTimeUnit.DayBased -> daysUntil(other) / unit.days
9797
}
9898

9999
public actual fun LocalDate.daysUntil(other: LocalDate): Int =

core/jvm/src/Instant.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,9 @@ public actual fun Instant.plus(value: Long, unit: DateTimeUnit, timeZone: TimeZo
133133
when (unit) {
134134
is DateTimeUnit.TimeBased ->
135135
plus(value, unit).value.also { it.atZone(timeZone.zoneId) }
136-
is DateTimeUnit.DateBased.DayBased ->
136+
is DateTimeUnit.DayBased ->
137137
thisZdt.plusDays(safeMultiply(value, unit.days.toLong())).toInstant()
138-
is DateTimeUnit.DateBased.MonthBased ->
138+
is DateTimeUnit.MonthBased ->
139139
thisZdt.plusMonths(safeMultiply(value, unit.months.toLong())).toInstant()
140140
}.let(::Instant)
141141
} catch (e: Exception) {
@@ -173,8 +173,8 @@ public actual fun Instant.until(other: Instant, unit: DateTimeUnit, timeZone: Ti
173173
val otherZdt = other.atZone(timeZone)
174174
when(unit) {
175175
is DateTimeUnit.TimeBased -> until(other, unit)
176-
is DateTimeUnit.DateBased.DayBased -> thisZdt.until(otherZdt, ChronoUnit.DAYS) / unit.days
177-
is DateTimeUnit.DateBased.MonthBased -> thisZdt.until(otherZdt, ChronoUnit.MONTHS) / unit.months
176+
is DateTimeUnit.DayBased -> thisZdt.until(otherZdt, ChronoUnit.DAYS) / unit.days
177+
is DateTimeUnit.MonthBased -> thisZdt.until(otherZdt, ChronoUnit.MONTHS) / unit.months
178178
}
179179
} catch (e: DateTimeException) {
180180
throw DateTimeArithmeticException(e)

core/jvm/src/LocalDate.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,11 @@ public actual fun LocalDate.minus(value: Int, unit: DateTimeUnit.DateBased): Loc
6363
public actual fun LocalDate.plus(value: Long, unit: DateTimeUnit.DateBased): LocalDate =
6464
try {
6565
when (unit) {
66-
is DateTimeUnit.DateBased.DayBased -> {
66+
is DateTimeUnit.DayBased -> {
6767
val addDays: Long = safeMultiply(value, unit.days.toLong())
6868
ofEpochDayChecked(safeAdd(this.value.toEpochDay(), addDays))
6969
}
70-
is DateTimeUnit.DateBased.MonthBased ->
70+
is DateTimeUnit.MonthBased ->
7171
this.value.plusMonths(safeMultiply(value, unit.months.toLong()))
7272
}.let(::LocalDate)
7373
} catch (e: Exception) {
@@ -109,8 +109,8 @@ public actual fun LocalDate.periodUntil(other: LocalDate): DatePeriod {
109109
}
110110

111111
public actual fun LocalDate.until(other: LocalDate, unit: DateTimeUnit.DateBased): Int = when(unit) {
112-
is DateTimeUnit.DateBased.MonthBased -> (this.value.until(other.value, ChronoUnit.MONTHS) / unit.months).clampToInt()
113-
is DateTimeUnit.DateBased.DayBased -> (this.value.until(other.value, ChronoUnit.DAYS) / unit.days).clampToInt()
112+
is DateTimeUnit.MonthBased -> (this.value.until(other.value, ChronoUnit.MONTHS) / unit.months).clampToInt()
113+
is DateTimeUnit.DayBased -> (this.value.until(other.value, ChronoUnit.DAYS) / unit.days).clampToInt()
114114
}
115115

116116
public actual fun LocalDate.daysUntil(other: LocalDate): Int =

core/jvm/src/TimeZoneJvm.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public actual open class TimeZone internal constructor(internal val zoneId: Zone
4444
internal fun ofZone(zoneId: ZoneId): TimeZone = when {
4545
zoneId is jtZoneOffset ->
4646
FixedOffsetTimeZone(UtcOffset(zoneId))
47-
zoneId.rules.isFixedOffset ->
47+
zoneId.isFixedOffset ->
4848
FixedOffsetTimeZone(UtcOffset(zoneId.normalized() as jtZoneOffset), zoneId)
4949
else ->
5050
TimeZone(zoneId)
@@ -54,6 +54,15 @@ public actual open class TimeZone internal constructor(internal val zoneId: Zone
5454
}
5555
}
5656

57+
// Workaround for https://issuetracker.google.com/issues/203956057
58+
private val ZoneId.isFixedOffset: Boolean
59+
get() = try {
60+
// On older Android versions, this can throw even though it shouldn't
61+
rules.isFixedOffset
62+
} catch (e: ArrayIndexOutOfBoundsException) {
63+
false // Happens for America/Costa_Rica, Africa/Cairo, Egypt
64+
}
65+
5766
@Serializable(with = FixedOffsetTimeZoneSerializer::class)
5867
public actual class FixedOffsetTimeZone
5968
internal constructor(public actual val offset: UtcOffset, zoneId: ZoneId): TimeZone(zoneId) {

0 commit comments

Comments
 (0)