diff --git a/app/src/main/java/to/bitkit/ext/DateTime.kt b/app/src/main/java/to/bitkit/ext/DateTime.kt index 69c94349d..8358e3871 100644 --- a/app/src/main/java/to/bitkit/ext/DateTime.kt +++ b/app/src/main/java/to/bitkit/ext/DateTime.kt @@ -29,6 +29,7 @@ import kotlin.time.Clock import kotlin.time.Duration.Companion.days import kotlin.time.Duration.Companion.milliseconds import kotlin.time.ExperimentalTime +import java.text.DateFormat as JavaDateFormat import java.time.LocalDate as JavaLocalDate import kotlin.time.Instant as KInstant @@ -68,10 +69,10 @@ fun Long.toDateUTC(): String { return dateTime.format(DateTimeFormatter.ofPattern("dd/MM/yyyy")) } -fun Long.toLocalizedTimestamp(locale: Locale = Locale.US): String { +fun Long.toLocalizedTimestamp(locale: Locale = Locale.getDefault()): String { val date = Date(this) val formatter = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT, ULocale.forLocale(locale)) - ?: return SimpleDateFormat("MMMM d, yyyy 'at' h:mm a", locale).format(date) + ?: return JavaDateFormat.getDateTimeInstance(JavaDateFormat.LONG, JavaDateFormat.SHORT, locale).format(date) return formatter.format(date) } diff --git a/app/src/test/java/to/bitkit/ext/DateTimeExtTest.kt b/app/src/test/java/to/bitkit/ext/DateTimeExtTest.kt index 5332e7091..cc2195098 100644 --- a/app/src/test/java/to/bitkit/ext/DateTimeExtTest.kt +++ b/app/src/test/java/to/bitkit/ext/DateTimeExtTest.kt @@ -20,6 +20,9 @@ class DateTimeExtTest : BaseUnitTest() { val AFTERNOON: Instant = Instant.parse("2026-03-07T15:23:00Z") val MIDNIGHT: Instant = Instant.parse("2026-03-07T00:15:00Z") val NOON: Instant = Instant.parse("2026-03-07T12:05:00Z") + + // Midday so the calendar day, and with it the month name, holds in every time zone + val MIDDAY_IN_JULY: Long = Instant.parse("2026-07-27T12:00:00Z").toEpochMilli() } @Test @@ -261,5 +264,40 @@ class DateTimeExtTest : BaseUnitTest() { assertEquals(UiDateStyle.DATE_TIME, uiDateStyleFor(lateEvening.epochSecond.toULong(), today, bucharest)) } + @Test + fun `toLocalizedTimestamp uses the supplied locale`() { + val inGerman = MIDDAY_IN_JULY.toLocalizedTimestamp(Locale.GERMANY) + val inUs = MIDDAY_IN_JULY.toLocalizedTimestamp(Locale.US) + + assertTrue(inGerman.contains("Juli"), "expected a German month name, got '$inGerman'") + assertTrue(inUs.contains("July"), "expected an English month name, got '$inUs'") + } + + @Test + fun `toLocalizedTimestamp follows the default locale when none is supplied`() { + val original = Locale.getDefault() + try { + Locale.setDefault(Locale.GERMANY) + val result = MIDDAY_IN_JULY.toLocalizedTimestamp() + + assertTrue(result.contains("Juli"), "expected a German month name, got '$result'") + } finally { + Locale.setDefault(original) + } + } + + @Test + fun `toLocalizedTimestamp orders the date the way the locale does`() { + val original = Locale.getDefault() + try { + Locale.setDefault(Locale.GERMANY) + val result = MIDDAY_IN_JULY.toLocalizedTimestamp() + + assertTrue(result.indexOf("27") < result.indexOf("Juli"), "expected day before month, got '$result'") + } finally { + Locale.setDefault(original) + } + } + private fun Instant.formattedInUtc(pattern: String) = formatted(pattern, Locale.US, UTC) } diff --git a/changelog.d/next/1124.fixed.md b/changelog.d/next/1124.fixed.md new file mode 100644 index 000000000..d5b925dd7 --- /dev/null +++ b/changelog.d/next/1124.fixed.md @@ -0,0 +1 @@ +App Status and Backup timestamps now follow the device language instead of always using the US date format.