Kotlin / kotlinx-datetime

KotlinX multiplatform date/time library
Apache License 2.0
2.39k stars 99 forks source link

fun LocalDate.atEndOfDayIn(timeZone: TimeZone): Instant #434

Closed vanniktech closed 3 weeks ago

vanniktech commented 3 weeks ago

Similar to

fun LocalDate.atStartOfDayIn(timeZone: TimeZone): Instant

I would like to have a atEndOfDayIn.

Some data is stored in a database and uses Instant for a created column. I want to filter this data by defining a start & end LocalDate. To construct my sql BETWEEN statementI can usestartLocalDate.atStartOfDayIn()but I don't have aatEndOfDayIn` for defining the end range.

dkhalanskyjb commented 3 weeks ago

Unfortunately, there is no such thing as "the last moment of a day". The best we can do is LocalDate(2024, 9, 9).atTime(23, 59, 59, 999_999_999), but that's code smell, as it implicitly makes the assumption that there will be no datetimes with sub-nanosecond portions. For most code bases, this assumption is certainly valid, but as a general-purpose datetime library, we can't rely on that.

Suggestion: instead of BETWEEN, can you use date.atStartOfDayIn(zone) <= created AND created < date.plus(1, DateTimeUnit.DAY).atStartOfDayIn(zone)?

vanniktech commented 3 weeks ago

Unfortunately, there is no such thing as "the last moment of a day"

It is because kotlinx date time does not have the necessary data? With atStartOfDayIn it is possible to figure out when for instance 0:00 midnight has been skipped due to daylight saving.

Suggestion: instead of BETWEEN, can you use date.atStartOfDayIn(zone) <= created AND created < date.plus(1, DateTimeUnit.DAY).atStartOfDayIn(zone)?

This I can do, yes.

dkhalanskyjb commented 3 weeks ago

It is because kotlinx date time does not have the necessary data?

No, it's because whatever moment you choose as the last moment of the day, you can choose a later moment of that same day. For example, if you choose 2024-09-09T23:59:59.999999999, then it's not the last moment: at least 2024-09-09T23:59:59.9999999999 is later than that. And so on.

If you're not bothered by this and define "the last moment of the day" as "the moment one nanosecond before the next day starts", you can do

fun LocalDate.atEndOfDayIn(timeZone: TimeZone) =
  plus(1, DateTimeUnit.DAY).atStartOfDayIn(timeZone) - 1.nanoseconds
vanniktech commented 3 weeks ago

Fair enough, thanks for the clarification.