Skip to content

Commit

Permalink
Improve the KDoc
Browse files Browse the repository at this point in the history
Fixes #347
  • Loading branch information
dkhalanskyjb committed Apr 29, 2024
1 parent e721269 commit b6a6338
Show file tree
Hide file tree
Showing 19 changed files with 644 additions and 96 deletions.
21 changes: 20 additions & 1 deletion core/common/src/Clock.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,26 @@ import kotlin.time.*
public interface Clock {
/**
* Returns the [Instant] corresponding to the current time, according to this clock.
*
* It is not guaranteed that calling [now] later will return a larger [Instant].
* In particular, for [System], violations of this are completely expected and must be taken into account.
* See the documentation of [System] for details.
*/
public fun now(): Instant

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

/**
* Returns a [TimeSource] that uses this [Clock] to mark a time instant and to find the amount of time elapsed since that mark.
*
* **Pitfall**: using this function with [Clock.System] is error-prone,
* because [Clock.System] is not well suited for measuring time intervals.
* Please only use this conversion function on the [Clock] instances that are fully controlled programmatically.
*/
@ExperimentalTime
public fun Clock.asTimeSource(): TimeSource.WithComparableMarks = object : TimeSource.WithComparableMarks {
Expand Down
57 changes: 50 additions & 7 deletions core/common/src/DateTimePeriod.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ package kotlinx.datetime
import kotlinx.datetime.internal.*
import kotlinx.datetime.serializers.DatePeriodIso8601Serializer
import kotlinx.datetime.serializers.DateTimePeriodIso8601Serializer
import kotlinx.datetime.serializers.DatePeriodComponentSerializer
import kotlinx.datetime.serializers.DateTimePeriodComponentSerializer
import kotlin.math.*
import kotlin.time.Duration
import kotlinx.serialization.Serializable
Expand All @@ -19,10 +21,29 @@ import kotlinx.serialization.Serializable
*
* The time components are: [hours], [minutes], [seconds], [nanoseconds].
*
* A `DateTimePeriod` can be constructed using the same-named constructor function,
* [parsed][DateTimePeriod.parse] from a string, or returned as the result of instant arithmetic operations (see [Instant.periodUntil]).
* All these functions can return a [DatePeriod] value, which is a subtype of `DateTimePeriod`,
* a special case that only stores date components, if all time components of the result happen to be zero.
* ### Interaction with other entities
*
* [DateTimePeriod] can be returned from [Instant.periodUntil], representing the difference between two instants.
* Conversely, there is an [Instant.plus] overload that accepts a [DateTimePeriod] and returns a new instant.
*
* [DatePeriod] is a subtype of [DateTimePeriod] that only stores the date components and has all time components equal
* to zero.
*
* ### Construction, serialization, and deserialization
*
* When a [DateTimePeriod] is constructed in any way, a [DatePeriod] value, which is a subtype of [DateTimePeriod],
* will be returned if all time components happen to be zero.
*
* A `DateTimePeriod` can be constructed using the constructor function with the same name.
*
* [parse] and [toString] methods can be used to obtain a [DateTimePeriod] from and convert it to a string in the
* ISO 8601 extended format (for example, `P1Y2M6DT13H`).
*
* or returned as the result of instant arithmetic operations (see [Instant.periodUntil]).
*
* Additionally, there are several `kotlinx-serialization` serializers for [DateTimePeriod]:
* - [DateTimePeriodIso8601Serializer] for the ISO 8601 format;
* - [DateTimePeriodComponentSerializer] for an object with components.
*/
@Serializable(with = DateTimePeriodIso8601Serializer::class)
// TODO: could be error-prone without explicitly named params
Expand All @@ -33,6 +54,7 @@ public sealed class DateTimePeriod {
* The number of calendar days.
*
* Note that a calendar day is not identical to 24 hours, see [DateTimeUnit.DayBased] for details.
* Also, this field does not overflow into months, so values larger than 30 can be present.
*/
public abstract val days: Int
internal abstract val totalNanoseconds: Long
Expand All @@ -49,6 +71,8 @@ public sealed class DateTimePeriod {

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

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

/**
* Converts this period to the ISO-8601 string representation for durations.
* Converts this period to the ISO-8601 string representation for durations, for example, `P2M1DT3H`.
*
* @see DateTimePeriod.parse
*/
Expand Down Expand Up @@ -304,10 +328,13 @@ public sealed class DateTimePeriod {
public fun String.toDateTimePeriod(): DateTimePeriod = DateTimePeriod.parse(this)

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

public companion object {
/**
* Parses the ISO-8601 duration representation as a [DatePeriod].
* Parses the ISO-8601 duration representation as a [DatePeriod], for example, `P1Y2M30D`.
*
* This function is equivalent to [DateTimePeriod.parse], but will fail if any of the time components are not
* zero.
Expand Down Expand Up @@ -422,6 +460,11 @@ public fun DateTimePeriod(
*
* If the duration value is too big to be represented as a [Long] number of nanoseconds,
* the result will be [Long.MAX_VALUE] nanoseconds.
*
* **Pitfall**: a [DateTimePeriod] obtained this way will always have zero date components.
* The reason is that even a [Duration] obtained via [Duration.Companion.days] just means a multiple of 24 hours,
* whereas in `kotlinx-datetime`, a day is a calendar day, which can be different from 24 hours.
* See [DateTimeUnit.DayBased] for details.
*/
// TODO: maybe it's more consistent to throw here on overflow?
public fun Duration.toDateTimePeriod(): DateTimePeriod = buildDateTimePeriod(totalNanoseconds = inWholeNanoseconds)
Expand Down
49 changes: 43 additions & 6 deletions core/common/src/DateTimeUnit.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,28 @@ import kotlin.time.Duration.Companion.nanoseconds
/**
* A unit for measuring time.
*
* This class is used to express arithmetic operations like addition and subtraction on date-time values:
* for example, adding 10 days to a date-time value, or subtracting 5 hours from a date-time value.
*
* ### Interaction with other entities
*
* Any [DateTimeUnit] can be used with [Instant.plus], [Instant.minus] to
* find an instant that is some number of units away from the given instant.
* Also, [Instant.until] can be used to find the number of the given units between two instants.
*
* [DateTimeUnit.TimeBased] can be used in the [Instant] operations without specifying the time zone, because
* [DateTimeUnit.TimeBased] is defined in terms of passage of real time, and is independent of the time zone.
* Note that a calendar day is not considered identical to 24 hours, so using it does require specifying the time zone.
* See [DateTimeUnit.DayBased] for a discussion.
*
* [DateTimeUnit.DateBased] units can be used in the [LocalDate] operations: [LocalDate.plus], [LocalDate.minus], and
* [LocalDate.until].
*
* Arithmetic operations on [LocalDateTime] are not provided.
* Please see the [LocalDateTime] documentation for a discussion.
*
* ### Construction, serialization, and deserialization
*
* See the predefined constants for time units, like [DateTimeUnit.NANOSECOND], [DateTimeUnit.DAY],
* [DateTimeUnit.MONTH], and others.
*
Expand All @@ -22,19 +44,28 @@ import kotlin.time.Duration.Companion.nanoseconds
* - By constructing an instance manually with [TimeBased], [DayBased], or [MonthBased]: for example,
* `TimeBased(nanoseconds = 10)`.
*
* Note that a calendar day is not considered identical to 24 hours. See [DateTimeUnit.DayBased] for a discussion.
* Also, [DateTimeUnit] can be serialized and deserialized using `kotlinx.serialization`:
* [DateTimeUnitSerializer], [DateBasedDateTimeUnitSerializer], [DayBasedDateTimeUnitSerializer],
* [MonthBasedDateTimeUnitSerializer], and [TimeBasedDateTimeUnitSerializer] are provided, with varying levels of
* specificity of the type they handle.
*/
@Serializable(with = DateTimeUnitSerializer::class)
public sealed class DateTimeUnit {

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

/**
* A date-time unit that has the precise time duration.
* A [date-time unit][DateTimeUnit] that has the precise time duration.
*
* Such units are independent of the time zone.
* Any such unit can be represented as some fixed number of nanoseconds.
*
* @see DateTimeUnit for a discussion of date-time units in general.
*/
@Serializable(with = TimeBasedDateTimeUnitSerializer::class)
public class TimeBased(
Expand Down Expand Up @@ -94,11 +125,13 @@ public sealed class DateTimeUnit {
}

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

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

/**
* A date-time unit equal to some number of months.
* A [date-time unit][DateTimeUnit] equal to some number of months.
*
* Since different months have different number of days, a `MonthBased`-unit cannot be expressed a multiple of some [DayBased]-unit.
*
* @see DateTimeUnit for a discussion of date-time units in general.
*/
@Serializable(with = MonthBasedDateTimeUnitSerializer::class)
public class MonthBased(
Expand Down
3 changes: 3 additions & 0 deletions core/common/src/DayOfWeek.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ package kotlinx.datetime

/**
* The enumeration class representing the days of the week.
*
* Usually acquired from [LocalDate.dayOfWeek], but can be constructed using the `DayOfWeek` factory function that
* accepts the ISO 8601 day number. This number can be obtained from the [isoDayNumber] property.
*/
public expect enum class DayOfWeek {
MONDAY,
Expand Down
4 changes: 2 additions & 2 deletions core/common/src/Exceptions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
package kotlinx.datetime

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

/**
* Thrown when attempting to construct a [TimeZone] with an invalid ID.
* Thrown when attempting to construct a [TimeZone] with an invalid ID or unavailable rules.
*/
public class IllegalTimeZoneException: IllegalArgumentException {
public constructor(): super()
Expand Down
Loading

0 comments on commit b6a6338

Please sign in to comment.