-
Notifications
You must be signed in to change notification settings - Fork 103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provide time only representation, e.g. LocalTime #57
Comments
(CC'ing myself on this issue) |
+1 for me. Having a simple object representing a TimeOfDay would be really helpful in a library. It could even encompass AM/PM if our American friends would like that. |
+1 |
After some thought, it does look like there is a real need for a data structure to represent time-of-day wall clock readings, so we are interested in adding it! The next step is to gather more details about the use cases: which particular operations are expected from such a data structure? For now, the following ones come to mind:
Anything else? |
We are currently using our own implementation of
Also were similar implementation is available under this project by @fluidsonic: |
Thanks @xsveda! Could you please describe what |
Sure, it is an Android app and we hate the system time picker so we allow user to pick the When it goes over 24h it resets so |
Last time I used (Java's) LocalTime for modeling Reminder entity, where user choose the time of the day they want to be repeatadly reminded.
|
That's basically it. |
@xsveda here is some alternative code for the use case you provided. Would you say that it reflects the intent better or worse than what you've presented? fun halfHourTimestamps(atDate: LocalDate, from: LocalTime, to: LocalTime, zone: TimeZone) =
generateSequence(LocalDateTime(atDate, from).toInstant(zone)) {
it + 30.minutes
}.map {
it.toLocalDateTime(zone).time
}.takeWhile {
it <= to
} The crucial difference is that this code takes daylight saving time transitions into account, which will rarely cause some instances of For example, clocks were shifted an hour back at 2008-11-02T02:00 in New York, so the following behavior is observed:
(note that both 01:00 and 01:30 are repeated twice, which reflects the fact that an hour after 01:00 it was 01:00 in New York that night) |
Interesting idea, I didn't think about it this way. I believe it may work for some use cases but not sure whether it would prefer it for ours.
On the other hand, for restaurant opened 24/7 it will generate correct time slots in the autumn when there is no 2 AM slot as time is shifted forward :) |
Does not seem all that terrible. For any fixed-offset time zones, the proposed solution works the same as the one you provided, so having a default of
I would argue that the duplicities should, in fact, not be filtered. If the time shift occurred outside of working hours, it won't be reflected in the schedule anyway, but if it occurred during the workday, then some time slots would have an ambiguous meaning. So, a user who made a reservation at 13:00 on a day when 13:00 occurs twice wouldn't know when the reservation actually begins and so would have to call the restaurant or do something else like that. If, however, duplicate entries were present, the user could conceivably remember (or be reminded by some text in the app) that there is a DST transition; then they would explicitly be making a reservation at the first time it's 13:00. The bottom line is that it looks like the domain you're modelling does require handling time zone transitions, you just simplified this for the sake of ease of use in exchange for robustness. This may be a perfectly valid tradeoff in your case, but, from the library design perspective, the choice to ignore transitions must be done explicitly and with the full understanding of the consequences, so it seems for now that the (problematic in many cases) Thanks for the elaboration, this does help a lot! |
We have a lot of cases where we need a For example we have a larger fasting feature where every fasting day has different fasting times which don't have a date: internal data class FastingTime(
val start: LocalTime,
val end: LocalTime,
val changed: Boolean
) Based on that time we derive additional logic like for example: private val FastingTime.isFullDayFasting: Boolean
get() {
return start == LocalTimeMin && end == LocalTimeMax
} |
I've needed some this too (Android + JVM)
This is what I have in import kotlinx.datetime.LocalDate
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.atTime
private const val MINUTES_PER_HOUR = 60
private const val SECONDS_PER_MINUTE = 60
private const val SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR
private const val NANOS_PER_SECOND = 1000_000_000L
private const val NANOS_PER_MINUTE = NANOS_PER_SECOND * SECONDS_PER_MINUTE
private const val NANOS_PER_HOUR = NANOS_PER_MINUTE * MINUTES_PER_HOUR
data class LocalTime(
val hour: Int,
val minute: Int,
val second: Int = 0,
val nanosecond: Int = 0,
) {
fun toSecondOfDay(): Int {
var total = hour * SECONDS_PER_HOUR
total += minute * SECONDS_PER_MINUTE
total += second
return total
}
fun toNanoOfDay(): Long {
var total: Long = hour * NANOS_PER_HOUR
total += minute * NANOS_PER_MINUTE
total += second * NANOS_PER_SECOND
total += nanosecond.toLong()
return total
}
companion object {
fun ofSecondOfDay(secondOfDay: Int): LocalTime {
var seconds = secondOfDay
val hours = (seconds / SECONDS_PER_HOUR)
seconds -= (hours * SECONDS_PER_HOUR)
val minutes = (seconds / SECONDS_PER_MINUTE)
seconds -= (minutes * SECONDS_PER_MINUTE)
return LocalTime(
hour = hours,
minute = minutes,
second = seconds,
)
}
fun ofNanoOfDay(nanoOfDay: Long): LocalTime {
var nanos = nanoOfDay
val hours = (nanos / NANOS_PER_HOUR)
nanos -= hours * NANOS_PER_HOUR
val minutes = (nanos / NANOS_PER_MINUTE)
nanos -= minutes * NANOS_PER_MINUTE
val seconds = (nanos / NANOS_PER_SECOND)
nanos -= seconds * NANOS_PER_SECOND
return LocalTime(
hour = hours.toInt(),
minute = minutes.toInt(),
second = seconds.toInt(),
nanosecond = nanos.toInt(),
)
}
}
}
val LocalDateTime.time get() = LocalTime(
hour = hour,
minute = minute,
second = second,
nanosecond = nanosecond,
)
fun LocalDate.atTime(localTime: LocalTime) = atTime(
hour = localTime.hour,
minute = localTime.minute,
second = localTime.second,
nanosecond = localTime.nanosecond,
) and for Android/JVM I also have: fun java.time.LocalTime.toKotlinLocalTime() = LocalTime(
hour = hour,
minute = minute,
second = second,
nanosecond = nano,
)
fun LocalTime.toJavaLocalTime() = java.time.LocalTime.of(
hour,
minute,
second,
nanosecond,
) Would this already be something that is helpful to others and if so can be pr'ed? I haven't worked out serialisation adapters as I'm only saving them to the database where I use |
This is also needed for date-time handling in https://github.com/akuleshov7/ktoml so @vanniktech did you make a PR (with serialization adapters) ? |
I did not since you're the first to respond. Personally, I don't need serialization adapters. I store my values as a If you have time, feel free to take my snippets and convert it into a PR, otherwise I can get back to it later this or next week. |
I'm gonna see if I get some time to do it :) |
I made a PR, @kluever @dkhalanskyjb could you maybe review it ? |
Hey,
Currently there is support for
LocalDateTime
, but I would like to use some time representation without a date. Ideall would be something likeLocalTime
for my use case.my use case:
represent daily events
my current workaround:
use
DateTimePeriod
with a max of 24h in totalThe text was updated successfully, but these errors were encountered: