You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently, iterating over a range of kotlinx-datetime types (LocalDate, LocalDateTime, Instant) with a specific step requires manual loop logic (e.g., using while and manually adding the step). This contrasts with standard Kotlin ranges (like IntRange, LongRange) which offer a convenient step() infix function for easy iteration.
Adding a similar step capability to kotlinx-datetime ranges would significantly improve usability for common tasks such as:
Generating data points at regular intervals (e.g., daily reports, hourly summaries).
Iterating through calendar views or schedules.
Processing time-series data with specific increments.
Proposed Solution (High-Level):
Introduce step infix extension functions that operate on ClosedRange where T is a kotlinx-datetime type. These functions would return an Iterable (or potentially a dedicated Progression type) allowing for iteration with a specified increment.
The appropriate step type would depend on the range type:
LocalDateRange: Step using DatePeriod.
InstantRange: Step using kotlin.time.Duration.
LocalDateTimeRange: Could potentially step using:
DatePeriod (affecting the date part only).
kotlin.time.Duration (affecting the whole date-time, but requires careful TimeZone handling).
(Possibly DateTimePeriod as well, also requiring TimeZone handling)
val startDate = LocalDate(2024, 1, 1)
val endDate = LocalDate(2024, 1, 10)
// Iterate Wednesdays within the range (or similar period logic)
val weeklyPeriod = DatePeriod(days = 7) // Or calculate specific period
// for (date in startDate..endDate step weeklyPeriod) { ... } // Example goal
// Iterate every 2 days
for (date in startDate..endDate step DatePeriod(days = 2)) {
println(date) // 2024-01-01, 2024-01-03, ..., 2024-01-09
}
val startInstant = Clock.System.now()
val endInstant = startInstant + 1.days
// Iterate every 6 hours
for (instant in startInstant..endInstant step 6.hours) {
println(instant)
}
val startDateTime = LocalDateTime(2024, 3, 10, 1, 30) // DST change example
val endDateTime = startDateTime + 2.days
// Iterate by DatePeriod (time remains 01:30)
for (ldt in startDateTime..endDateTime step DatePeriod(days = 1)) {
println(ldt) // 2024-03-10 01:30, 2024-03-11 01:30, 2024-03-12 01:30
}
// Iterate by Duration (requires TimeZone context)
val zone = TimeZone.of("America/New_York")
// How should TimeZone be provided? This needs discussion.
// Example hypothetical API:
// for (ldt in startDateTime..endDateTime step (6.hours using zone)) {
// println(ldt) // e.g., 2024-03-10 01:30, 2024-03-10 07:30, ... (respecting DST)
// }`
Request for Feedback:
Would the kotlinx-datetime maintainers be interested in adding such step functionality to the library? If so, what would be the preferred API design, particularly regarding the TimeZone requirement for LocalDateTime steps involving time components (Duration, DateTimePeriod)?
I'd be potentially interested in contributing an implementation if a clear direction is established.
Thank you for considering this proposal.
The text was updated successfully, but these errors were encountered:
LocalDateRange: we are about to merge Local date range #189, which adds this. Here's its discussion: Adding LocalDateRange #190, explaining why DatePeriod is not used for defining the step length.
InstantRange: if Duration is indeed used for stepping, then given that Instant is going to be moved into the standard library (Consider moving Instant and Clock to the standard library #382) and Duration is already there, it's completely outside the scope of kotlinx-datetime. Please use https://kotl.in/issue and describe your specific use case (business logic) there if you have one. During my research into how kotlinx-datetime is used, I haven't encountered many cases where it would be useful, though: usually, people stick to dates when iterating over time periods.
LocalDateTimeRange: we are not going to add that. Please see https://github.com/Kotlin/kotlinx-datetime?tab=readme-ov-file#date--time-arithmetic for an explanation of our approach to date + time arithmetic. As an example, val endDateTime = startDateTime + 2.days from your example will not compile in today's state of the library, and it shouldn't, as 2.days returns a Duration equal to 48 hours, not two calendar days, so adding it to a LocalDateTime is not a well-defined operation when no timezone is provided.
The only part of this proposal that is up for consideration is InstantRange, and that's a request for the standard library, so closing the issue.
Motivation:
Currently, iterating over a range of kotlinx-datetime types (LocalDate, LocalDateTime, Instant) with a specific step requires manual loop logic (e.g., using while and manually adding the step). This contrasts with standard Kotlin ranges (like IntRange, LongRange) which offer a convenient step() infix function for easy iteration.
Adding a similar step capability to kotlinx-datetime ranges would significantly improve usability for common tasks such as:
Generating data points at regular intervals (e.g., daily reports, hourly summaries).
Iterating through calendar views or schedules.
Processing time-series data with specific increments.
Proposed Solution (High-Level):
Introduce step infix extension functions that operate on ClosedRange where T is a kotlinx-datetime type. These functions would return an Iterable (or potentially a dedicated Progression type) allowing for iteration with a specified increment.
The appropriate step type would depend on the range type:
LocalDateRange: Step using DatePeriod.
InstantRange: Step using kotlin.time.Duration.
LocalDateTimeRange: Could potentially step using:
Example Usage:
`import kotlinx.datetime.*
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.days
val startDate = LocalDate(2024, 1, 1)
val endDate = LocalDate(2024, 1, 10)
// Iterate Wednesdays within the range (or similar period logic)
val weeklyPeriod = DatePeriod(days = 7) // Or calculate specific period
// for (date in startDate..endDate step weeklyPeriod) { ... } // Example goal
// Iterate every 2 days
for (date in startDate..endDate step DatePeriod(days = 2)) {
println(date) // 2024-01-01, 2024-01-03, ..., 2024-01-09
}
val startInstant = Clock.System.now()
val endInstant = startInstant + 1.days
// Iterate every 6 hours
for (instant in startInstant..endInstant step 6.hours) {
println(instant)
}
val startDateTime = LocalDateTime(2024, 3, 10, 1, 30) // DST change example
val endDateTime = startDateTime + 2.days
// Iterate by DatePeriod (time remains 01:30)
for (ldt in startDateTime..endDateTime step DatePeriod(days = 1)) {
println(ldt) // 2024-03-10 01:30, 2024-03-11 01:30, 2024-03-12 01:30
}
// Iterate by Duration (requires TimeZone context)
val zone = TimeZone.of("America/New_York")
// How should TimeZone be provided? This needs discussion.
// Example hypothetical API:
// for (ldt in startDateTime..endDateTime step (6.hours using zone)) {
// println(ldt) // e.g., 2024-03-10 01:30, 2024-03-10 07:30, ... (respecting DST)
// }`
Request for Feedback:
Would the kotlinx-datetime maintainers be interested in adding such step functionality to the library? If so, what would be the preferred API design, particularly regarding the TimeZone requirement for LocalDateTime steps involving time components (Duration, DateTimePeriod)?
I'd be potentially interested in contributing an implementation if a clear direction is established.
Thank you for considering this proposal.
The text was updated successfully, but these errors were encountered: