Skip to content

Commit 4add323

Browse files
committed
Improve the KDoc
Fixes #347
1 parent 9d59199 commit 4add323

19 files changed

+644
-96
lines changed

core/common/src/Clock.kt

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,26 @@ import kotlin.time.*
1515
public interface Clock {
1616
/**
1717
* Returns the [Instant] corresponding to the current time, according to this clock.
18+
*
19+
* It is not guaranteed that calling [now] later will return a larger [Instant].
20+
* In particular, for [System], violations of this are completely expected and must be taken into account.
21+
* See the documentation of [System] for details.
1822
*/
1923
public fun now(): Instant
2024

2125
/**
22-
* The [Clock] instance that queries the operating system as its source of knowledge of time.
26+
* The [Clock] instance that queries the operating system as its source of time knowledge.
27+
*
28+
* Successive calls to [now] will not necessarily return increasing [Instant] values, and when they do,
29+
* these increases will not necessarily correspond to the elapsed time.
30+
*
31+
* For example, when using [Clock.System], the following could happen:
32+
* - [now] returns `2023-01-02T22:35:01Z`;
33+
* - The system queries the Internet and recognizes that its clock needs adjusting;
34+
* - [now] returns `2023-01-02T22:32:05Z`.
35+
*
36+
* When predictable intervals between successive measurements are needed, consider using
37+
* [TimeSource.Monotonic].
2338
*/
2439
public object System : Clock {
2540
override fun now(): Instant = @Suppress("DEPRECATION_ERROR") Instant.now()
@@ -38,6 +53,10 @@ public fun Clock.todayIn(timeZone: TimeZone): LocalDate =
3853

3954
/**
4055
* Returns a [TimeSource] that uses this [Clock] to mark a time instant and to find the amount of time elapsed since that mark.
56+
*
57+
* **Pitfall**: using this function with [Clock.System] is error-prone,
58+
* because [Clock.System] is not well suited for measuring time intervals.
59+
* Please only use this conversion function on the [Clock] instances that are fully controlled programmatically.
4160
*/
4261
@ExperimentalTime
4362
public fun Clock.asTimeSource(): TimeSource.WithComparableMarks = object : TimeSource.WithComparableMarks {

core/common/src/DateTimePeriod.kt

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ package kotlinx.datetime
88
import kotlinx.datetime.internal.*
99
import kotlinx.datetime.serializers.DatePeriodIso8601Serializer
1010
import kotlinx.datetime.serializers.DateTimePeriodIso8601Serializer
11+
import kotlinx.datetime.serializers.DatePeriodComponentSerializer
12+
import kotlinx.datetime.serializers.DateTimePeriodComponentSerializer
1113
import kotlin.math.*
1214
import kotlin.time.Duration
1315
import kotlinx.serialization.Serializable
@@ -19,10 +21,29 @@ import kotlinx.serialization.Serializable
1921
*
2022
* The time components are: [hours], [minutes], [seconds], [nanoseconds].
2123
*
22-
* A `DateTimePeriod` can be constructed using the same-named constructor function,
23-
* [parsed][DateTimePeriod.parse] from a string, or returned as the result of instant arithmetic operations (see [Instant.periodUntil]).
24-
* All these functions can return a [DatePeriod] value, which is a subtype of `DateTimePeriod`,
25-
* a special case that only stores date components, if all time components of the result happen to be zero.
24+
* ### Interaction with other entities
25+
*
26+
* [DateTimePeriod] can be returned from [Instant.periodUntil], representing the difference between two instants.
27+
* Conversely, there is an [Instant.plus] overload that accepts a [DateTimePeriod] and returns a new instant.
28+
*
29+
* [DatePeriod] is a subtype of [DateTimePeriod] that only stores the date components and has all time components equal
30+
* to zero.
31+
*
32+
* ### Construction, serialization, and deserialization
33+
*
34+
* When a [DateTimePeriod] is constructed in any way, a [DatePeriod] value, which is a subtype of [DateTimePeriod],
35+
* will be returned if all time components happen to be zero.
36+
*
37+
* A `DateTimePeriod` can be constructed using the constructor function with the same name.
38+
*
39+
* [parse] and [toString] methods can be used to obtain a [DateTimePeriod] from and convert it to a string in the
40+
* ISO 8601 extended format (for example, `P1Y2M6DT13H`).
41+
*
42+
* or returned as the result of instant arithmetic operations (see [Instant.periodUntil]).
43+
*
44+
* Additionally, there are several `kotlinx-serialization` serializers for [DateTimePeriod]:
45+
* - [DateTimePeriodIso8601Serializer] for the ISO 8601 format;
46+
* - [DateTimePeriodComponentSerializer] for an object with components.
2647
*/
2748
@Serializable(with = DateTimePeriodIso8601Serializer::class)
2849
// TODO: could be error-prone without explicitly named params
@@ -33,6 +54,7 @@ public sealed class DateTimePeriod {
3354
* The number of calendar days.
3455
*
3556
* Note that a calendar day is not identical to 24 hours, see [DateTimeUnit.DayBased] for details.
57+
* Also, this field does not overflow into months, so values larger than 30 can be present.
3658
*/
3759
public abstract val days: Int
3860
internal abstract val totalNanoseconds: Long
@@ -49,6 +71,8 @@ public sealed class DateTimePeriod {
4971

5072
/**
5173
* The number of whole hours in this period.
74+
*
75+
* This field does not overflow into days, so values larger than 23 can be present.
5276
*/
5377
public open val hours: Int get() = (totalNanoseconds / 3_600_000_000_000).toInt()
5478

@@ -72,7 +96,7 @@ public sealed class DateTimePeriod {
7296
totalMonths <= 0 && days <= 0 && totalNanoseconds <= 0 && (totalMonths or days != 0 || totalNanoseconds != 0L)
7397

7498
/**
75-
* Converts this period to the ISO-8601 string representation for durations.
99+
* Converts this period to the ISO-8601 string representation for durations, for example, `P2M1DT3H`.
76100
*
77101
* @see DateTimePeriod.parse
78102
*/
@@ -304,10 +328,13 @@ public sealed class DateTimePeriod {
304328
public fun String.toDateTimePeriod(): DateTimePeriod = DateTimePeriod.parse(this)
305329

306330
/**
307-
* A special case of [DateTimePeriod] that only stores date components and has all time components equal to zero.
331+
* A special case of [DateTimePeriod] that only stores the date components and has all time components equal to zero.
308332
*
309333
* A `DatePeriod` is automatically returned from all constructor functions for [DateTimePeriod] if it turns out that
310334
* the time components are zero.
335+
* Additionally, [DatePeriod] has its own constructor, the [parse] function that will fail if any of the time components
336+
* are not zero, and [DatePeriodIso8601Serializer] and [DatePeriodComponentSerializer], mirroring those of
337+
* [DateTimePeriod].
311338
*
312339
* `DatePeriod` values are used in operations on [LocalDates][LocalDate] and are returned from operations on [LocalDates][LocalDate],
313340
* but they also can be passed anywhere a [DateTimePeriod] is expected.
@@ -317,6 +344,17 @@ public class DatePeriod internal constructor(
317344
internal override val totalMonths: Int,
318345
override val days: Int,
319346
) : DateTimePeriod() {
347+
/**
348+
* Constructs a new [DatePeriod].
349+
*
350+
* It is recommended to always explicitly name the arguments when constructing this manually,
351+
* like `DatePeriod(years = 1, months = 12)`.
352+
*
353+
* The passed numbers are not stored as is but are normalized instead for human readability, so, for example,
354+
* `DateTimePeriod(months = 24)` becomes `DateTimePeriod(years = 2)`.
355+
*
356+
* @throws IllegalArgumentException if the total number of months in [years] and [months] overflows an [Int].
357+
*/
320358
public constructor(years: Int = 0, months: Int = 0, days: Int = 0): this(totalMonths(years, months), days)
321359
// avoiding excessive computations
322360
/** The number of whole hours in this period. Always equal to zero. */
@@ -334,7 +372,7 @@ public class DatePeriod internal constructor(
334372

335373
public companion object {
336374
/**
337-
* Parses the ISO-8601 duration representation as a [DatePeriod].
375+
* Parses the ISO-8601 duration representation as a [DatePeriod], for example, `P1Y2M30D`.
338376
*
339377
* This function is equivalent to [DateTimePeriod.parse], but will fail if any of the time components are not
340378
* zero.
@@ -422,6 +460,11 @@ public fun DateTimePeriod(
422460
*
423461
* If the duration value is too big to be represented as a [Long] number of nanoseconds,
424462
* the result will be [Long.MAX_VALUE] nanoseconds.
463+
*
464+
* **Pitfall**: a [DateTimePeriod] obtained this way will always have zero date components.
465+
* The reason is that even a [Duration] obtained via [Duration.Companion.days] just means a multiple of 24 hours,
466+
* whereas in `kotlinx-datetime`, a day is a calendar day, which can be different from 24 hours.
467+
* See [DateTimeUnit.DayBased] for details.
425468
*/
426469
// TODO: maybe it's more consistent to throw here on overflow?
427470
public fun Duration.toDateTimePeriod(): DateTimePeriod = buildDateTimePeriod(totalNanoseconds = inWholeNanoseconds)

core/common/src/DateTimeUnit.kt

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,28 @@ import kotlin.time.Duration.Companion.nanoseconds
1414
/**
1515
* A unit for measuring time.
1616
*
17+
* This class is used to express arithmetic operations like addition and subtraction on date-time values:
18+
* for example, adding 10 days to a date-time value, or subtracting 5 hours from a date-time value.
19+
*
20+
* ### Interaction with other entities
21+
*
22+
* Any [DateTimeUnit] can be used with [Instant.plus], [Instant.minus] to
23+
* find an instant that is some number of units away from the given instant.
24+
* Also, [Instant.until] can be used to find the number of the given units between two instants.
25+
*
26+
* [DateTimeUnit.TimeBased] can be used in the [Instant] operations without specifying the time zone, because
27+
* [DateTimeUnit.TimeBased] is defined in terms of passage of real time, and is independent of the time zone.
28+
* Note that a calendar day is not considered identical to 24 hours, so using it does require specifying the time zone.
29+
* See [DateTimeUnit.DayBased] for a discussion.
30+
*
31+
* [DateTimeUnit.DateBased] units can be used in the [LocalDate] operations: [LocalDate.plus], [LocalDate.minus], and
32+
* [LocalDate.until].
33+
*
34+
* Arithmetic operations on [LocalDateTime] are not provided.
35+
* Please see the [LocalDateTime] documentation for a discussion.
36+
*
37+
* ### Construction, serialization, and deserialization
38+
*
1739
* See the predefined constants for time units, like [DateTimeUnit.NANOSECOND], [DateTimeUnit.DAY],
1840
* [DateTimeUnit.MONTH], and others.
1941
*
@@ -22,19 +44,28 @@ import kotlin.time.Duration.Companion.nanoseconds
2244
* - By constructing an instance manually with [TimeBased], [DayBased], or [MonthBased]: for example,
2345
* `TimeBased(nanoseconds = 10)`.
2446
*
25-
* Note that a calendar day is not considered identical to 24 hours. See [DateTimeUnit.DayBased] for a discussion.
47+
* Also, [DateTimeUnit] can be serialized and deserialized using `kotlinx.serialization`:
48+
* [DateTimeUnitSerializer], [DateBasedDateTimeUnitSerializer], [DayBasedDateTimeUnitSerializer],
49+
* [MonthBasedDateTimeUnitSerializer], and [TimeBasedDateTimeUnitSerializer] are provided, with varying levels of
50+
* specificity of the type they handle.
2651
*/
2752
@Serializable(with = DateTimeUnitSerializer::class)
2853
public sealed class DateTimeUnit {
2954

30-
/** Produces a date-time unit that is a multiple of this unit times the specified integer [scalar] value. */
55+
/**
56+
* Produces a date-time unit that is a multiple of this unit times the specified integer [scalar] value.
57+
*
58+
* @throws ArithmeticException if the result overflows.
59+
*/
3160
public abstract operator fun times(scalar: Int): DateTimeUnit
3261

3362
/**
34-
* A date-time unit that has the precise time duration.
63+
* A [date-time unit][DateTimeUnit] that has the precise time duration.
3564
*
3665
* Such units are independent of the time zone.
3766
* Any such unit can be represented as some fixed number of nanoseconds.
67+
*
68+
* @see DateTimeUnit for a discussion of date-time units in general.
3869
*/
3970
@Serializable(with = TimeBasedDateTimeUnitSerializer::class)
4071
public class TimeBased(
@@ -94,11 +125,13 @@ public sealed class DateTimeUnit {
94125
}
95126

96127
/**
97-
* A date-time unit equal to some number of days or months.
128+
* A [date-time unit][DateTimeUnit] equal to some number of days or months.
98129
*
99130
* Operations involving `DateBased` units are performed on dates. The same operations on [Instants][Instant]
100131
* require a [TimeZone] to find the corresponding [LocalDateTimes][LocalDateTime] first to perform
101132
* the operation with the date component of these `LocalDateTime` values.
133+
*
134+
* @see DateTimeUnit for a discussion of date-time units in general.
102135
*/
103136
@Serializable(with = DateBasedDateTimeUnitSerializer::class)
104137
public sealed class DateBased : DateTimeUnit() {
@@ -111,14 +144,16 @@ public sealed class DateTimeUnit {
111144
}
112145

113146
/**
114-
* A date-time unit equal to some number of calendar days.
147+
* A [date-time unit][DateTimeUnit] equal to some number of calendar days.
115148
*
116149
* A calendar day is not considered identical to 24 hours, thus a `DayBased`-unit cannot be expressed as a multiple of some [TimeBased]-unit.
117150
*
118151
* The reason lies in time zone transitions, because of which some days can be 23 or 25 hours.
119152
* For example, we say that exactly a whole day has passed between `2019-10-27T02:59` and `2019-10-28T02:59`
120153
* in Berlin, despite the fact that the clocks were turned back one hour, so there are, in fact, 25 hours
121154
* between the two date-times.
155+
*
156+
* @see DateTimeUnit for a discussion of date-time units in general.
122157
*/
123158
@Serializable(with = DayBasedDateTimeUnitSerializer::class)
124159
public class DayBased(
@@ -145,9 +180,11 @@ public sealed class DateTimeUnit {
145180
}
146181

147182
/**
148-
* A date-time unit equal to some number of months.
183+
* A [date-time unit][DateTimeUnit] equal to some number of months.
149184
*
150185
* Since different months have different number of days, a `MonthBased`-unit cannot be expressed a multiple of some [DayBased]-unit.
186+
*
187+
* @see DateTimeUnit for a discussion of date-time units in general.
151188
*/
152189
@Serializable(with = MonthBasedDateTimeUnitSerializer::class)
153190
public class MonthBased(

core/common/src/DayOfWeek.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ package kotlinx.datetime
77

88
/**
99
* The enumeration class representing the days of the week.
10+
*
11+
* Usually acquired from [LocalDate.dayOfWeek], but can be constructed using the `DayOfWeek` factory function that
12+
* accepts the ISO 8601 day number. This number can be obtained from the [isoDayNumber] property.
1013
*/
1114
public expect enum class DayOfWeek {
1215
MONDAY,

core/common/src/Exceptions.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
package kotlinx.datetime
77

88
/**
9-
* Thrown by date-time arithmetic operations if the result can not be computed or represented.
9+
* Thrown by date-time arithmetic operations if the result cannot be computed or represented.
1010
*/
1111
public class DateTimeArithmeticException: RuntimeException {
1212
public constructor(): super()
@@ -16,7 +16,7 @@ public class DateTimeArithmeticException: RuntimeException {
1616
}
1717

1818
/**
19-
* Thrown when attempting to construct a [TimeZone] with an invalid ID.
19+
* Thrown when attempting to construct a [TimeZone] with an invalid ID or unavailable rules.
2020
*/
2121
public class IllegalTimeZoneException: IllegalArgumentException {
2222
public constructor(): super()

0 commit comments

Comments
 (0)