core-time: add formatDateTimeCompact for dense list rows
Drops the year in the current year and drops the time when it carries no information (all-day items or a midnight time), so list rows show glanceable dates like "20 Jun" or "20 Jun · 14:30". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,13 @@
|
||||
package de.jeanlucmakiola.floret.time
|
||||
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalTime
|
||||
import java.time.ZoneId
|
||||
import java.time.chrono.IsoChronology
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.format.DateTimeFormatterBuilder
|
||||
import java.time.format.FormatStyle
|
||||
import java.util.Locale
|
||||
import kotlin.time.Instant
|
||||
|
||||
/**
|
||||
@@ -26,3 +31,28 @@ fun Instant.formatTime(): String = atSystemZone().format(timeFormatter)
|
||||
/** Date alone for all-day items, otherwise date + time. */
|
||||
fun Instant.formatDateTime(allDay: Boolean): String =
|
||||
if (allDay) formatDate() else "${formatDate()} · ${formatTime()}"
|
||||
|
||||
// The locale's medium date pattern with the year token stripped, e.g. "20 Jun" /
|
||||
// "Jun 20" — derived from the pattern so day/month order still follows the locale.
|
||||
// Built once; locale changes within a running process are rare enough to ignore.
|
||||
private val dateNoYearFormatter: DateTimeFormatter = run {
|
||||
val medium = DateTimeFormatterBuilder.getLocalizedDateTimePattern(
|
||||
FormatStyle.MEDIUM, null, IsoChronology.INSTANCE, Locale.getDefault(),
|
||||
)
|
||||
val noYear = medium.replace(Regex("[\\s.,/'’-]*y+[\\s.,/'’-]*"), " ").trim()
|
||||
DateTimeFormatter.ofPattern(noYear, Locale.getDefault())
|
||||
}
|
||||
|
||||
/**
|
||||
* Compact form for dense list rows: the year is dropped when the date is in the
|
||||
* current year, and the time is dropped when it carries no information (all-day
|
||||
* items, or a midnight time). Examples: "20 Jun", "20 Jun · 14:30", "20 Jun 2027".
|
||||
*/
|
||||
fun Instant.formatDateTimeCompact(allDay: Boolean): String {
|
||||
val zdt = atSystemZone()
|
||||
val datePart =
|
||||
if (zdt.year == LocalDate.now(ZoneId.systemDefault()).year) zdt.format(dateNoYearFormatter)
|
||||
else formatDate()
|
||||
return if (allDay || zdt.toLocalTime() == LocalTime.MIDNIGHT) datePart
|
||||
else "$datePart · ${formatTime()}"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user