Format the "updated" timestamp as a locale-aware date/time
Replaces the raw "2026-09-10 10:03:54" with each platform's own locale-formatted, no-seconds rendering (e.g. "Sep 10, 2026, 10:03 AM" in en-US) — mirroring how amounts are already locale-formatted elsewhere (NumberFormat.kt). Android uses the pre-java.time Calendar/DateFormat APIs since minSdk 24 predates java.time (API 26) and the project has no core library desugaring configured. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FXcrACM5sok3M1KQJ8kByy
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
package xyz.tyiu.satsprice.domain
|
||||
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import java.text.DateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Locale
|
||||
|
||||
// java.time requires API 26+ (this app's minSdk is 24) without core library desugaring, so this
|
||||
// uses the older Calendar/DateFormat APIs instead, same as pre-java.time Android code always did.
|
||||
actual fun localizedDateTime(dateTime: LocalDateTime): String {
|
||||
val calendar = Calendar.getInstance().apply {
|
||||
clear()
|
||||
set(dateTime.year, dateTime.monthNumber - 1, dateTime.dayOfMonth, dateTime.hour, dateTime.minute)
|
||||
}
|
||||
val formatter = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT, Locale.getDefault())
|
||||
return formatter.format(calendar.time)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package xyz.tyiu.satsprice.domain
|
||||
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import platform.Foundation.NSCalendar
|
||||
import platform.Foundation.NSDateComponents
|
||||
import platform.Foundation.NSDateFormatter
|
||||
import platform.Foundation.NSDateFormatterMediumStyle
|
||||
import platform.Foundation.NSDateFormatterShortStyle
|
||||
import platform.Foundation.NSLocale
|
||||
import platform.Foundation.currentLocale
|
||||
|
||||
actual fun localizedDateTime(dateTime: LocalDateTime): String {
|
||||
val components = NSDateComponents().apply {
|
||||
year = dateTime.year.toLong()
|
||||
month = dateTime.monthNumber.toLong()
|
||||
day = dateTime.dayOfMonth.toLong()
|
||||
hour = dateTime.hour.toLong()
|
||||
minute = dateTime.minute.toLong()
|
||||
}
|
||||
val date = NSCalendar.currentCalendar.dateFromComponents(components) ?: return dateTime.toString()
|
||||
val formatter = NSDateFormatter().apply {
|
||||
dateStyle = NSDateFormatterMediumStyle
|
||||
timeStyle = NSDateFormatterShortStyle
|
||||
locale = NSLocale.currentLocale
|
||||
}
|
||||
return formatter.stringFromDate(date)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package xyz.tyiu.satsprice.domain
|
||||
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
|
||||
/**
|
||||
* A locale-aware, human-readable rendering of [dateTime] (e.g. "Sep 10, 2026, 10:03 AM" in
|
||||
* en-US), using each platform's own date/time formatter — mirroring how [localizedGroupedInteger]
|
||||
* and [localizedDecimalSeparator] format numbers. Deliberately drops seconds: a "last updated"
|
||||
* label doesn't need second-level precision.
|
||||
*/
|
||||
expect fun localizedDateTime(dateTime: LocalDateTime): String
|
||||
@@ -5,6 +5,7 @@ import kotlinx.datetime.toLocalDateTime
|
||||
import xyz.tyiu.satsprice.CurrencyInfo
|
||||
import xyz.tyiu.satsprice.domain.CurrencyConverter
|
||||
import xyz.tyiu.satsprice.domain.formatAmount
|
||||
import xyz.tyiu.satsprice.domain.localizedDateTime
|
||||
import xyz.tyiu.satsprice.domain.toBigDecimalOrNull
|
||||
import kotlin.time.Instant
|
||||
|
||||
@@ -52,7 +53,5 @@ fun ConverterUiState.unselectedCurrencies(): List<CurrencyInfo> =
|
||||
/** Whether the active price source quotes a rate for [code] — every currency is listed regardless. */
|
||||
fun ConverterUiState.isPriced(code: String): Boolean = code in pricedCurrencyCodes
|
||||
|
||||
private fun Instant.toDateTimeString(): String {
|
||||
val local = toLocalDateTime(TimeZone.currentSystemDefault())
|
||||
return local.toString().substringBefore('.').replace('T', ' ')
|
||||
}
|
||||
private fun Instant.toDateTimeString(): String =
|
||||
localizedDateTime(toLocalDateTime(TimeZone.currentSystemDefault()))
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package xyz.tyiu.satsprice.domain
|
||||
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import kotlinx.datetime.toJavaLocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.format.FormatStyle
|
||||
import java.util.Locale
|
||||
|
||||
actual fun localizedDateTime(dateTime: LocalDateTime): String {
|
||||
val formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.SHORT)
|
||||
.withLocale(Locale.getDefault())
|
||||
return dateTime.toJavaLocalDateTime().format(formatter)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package xyz.tyiu.satsprice.domain
|
||||
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
|
||||
// Individual Int fields (rather than the LocalDateTime itself) cross the js() boundary, matching
|
||||
// the rest of this file's web interop — see SystemCurrencies.web.kt for why.
|
||||
private fun jsFormatDateTime(year: Int, month: Int, day: Int, hour: Int, minute: Int): String = js(
|
||||
"""(function() {
|
||||
var date = new Date(year, month - 1, day, hour, minute);
|
||||
var fmt = new Intl.DateTimeFormat(undefined, { dateStyle: 'medium', timeStyle: 'short' });
|
||||
return fmt.format(date);
|
||||
})()""",
|
||||
)
|
||||
|
||||
actual fun localizedDateTime(dateTime: LocalDateTime): String =
|
||||
jsFormatDateTime(dateTime.year, dateTime.monthNumber, dateTime.dayOfMonth, dateTime.hour, dateTime.minute)
|
||||
Reference in New Issue
Block a user