From b605d24a4d6251821e170725ff62b4d1710d7498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=96=D0=B8=D1=80=D0=BA=D0=B5=D0=B2=D0=B8=D1=87?= Date: Thu, 29 Feb 2024 21:29:54 +0300 Subject: [PATCH 1/4] locale-aware date formatting for desktop --- .../material3/PlatformDateFormat.desktop.kt | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/PlatformDateFormat.desktop.kt b/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/PlatformDateFormat.desktop.kt index 94ce9b959d313..ece5a0ca1f529 100644 --- a/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/PlatformDateFormat.desktop.kt +++ b/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/PlatformDateFormat.desktop.kt @@ -19,9 +19,14 @@ package androidx.compose.material3 import java.text.DateFormat import java.text.SimpleDateFormat import java.time.DayOfWeek +import java.time.Instant +import java.time.ZoneOffset +import java.time.format.DateTimeFormatter +import java.time.format.FormatStyle import java.time.format.TextStyle +@OptIn(ExperimentalMaterial3Api::class) internal actual class PlatformDateFormat actual constructor(private val locale: CalendarLocale) { private val delegate = LegacyCalendarModelImpl(locale) @@ -47,11 +52,22 @@ internal actual class PlatformDateFormat actual constructor(private val locale: // Maybe it will be supported in kotlinx.datetime in the future. // See https://github.com/Kotlin/kotlinx-datetime/pull/251 - // stub: not localized but at least readable variant + // date picker headline and semantics are localized, + // year picker is transformed to readable format val pattern = when(skeleton){ + DatePickerDefaults.YearAbbrMonthDaySkeleton -> { + return DateTimeFormatter + .ofLocalizedDate(FormatStyle.LONG) + .localizedBy(locale) + .format(Instant.ofEpochMilli(utcTimeMillis).atOffset(ZoneOffset.UTC)) + } + DatePickerDefaults.YearMonthWeekdayDaySkeleton -> { + return DateTimeFormatter + .ofLocalizedDate(FormatStyle.FULL) + .localizedBy(locale) + .format(Instant.ofEpochMilli(utcTimeMillis).atOffset(ZoneOffset.UTC)) + } DatePickerDefaults.YearMonthSkeleton -> "MMMM yyyy" - DatePickerDefaults.YearAbbrMonthDaySkeleton -> "MMM d, yyyy" - DatePickerDefaults.YearMonthWeekdayDaySkeleton -> "EEEE, MMMM d, yyyy" else -> skeleton } return formatWithPattern(utcTimeMillis, pattern) From 106d9d9361e414386304fef52f3c0d69ea080963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=96=D0=B8=D1=80=D0=BA=D0=B5=D0=B2=D0=B8=D1=87?= Date: Thu, 29 Feb 2024 21:37:54 +0300 Subject: [PATCH 2/4] extract formatter --- .../material3/PlatformDateFormat.desktop.kt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/PlatformDateFormat.desktop.kt b/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/PlatformDateFormat.desktop.kt index ece5a0ca1f529..3b82bcd68031b 100644 --- a/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/PlatformDateFormat.desktop.kt +++ b/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/PlatformDateFormat.desktop.kt @@ -33,6 +33,12 @@ internal actual class PlatformDateFormat actual constructor(private val locale: actual val firstDayOfWeek: Int get() = delegate.firstDayOfWeek + private val dateFormatter by lazy { + DateTimeFormatter + .ofLocalizedDate(FormatStyle.LONG) + .localizedBy(locale) + } + actual fun formatWithPattern( utcTimeMillis: Long, pattern: String, @@ -54,17 +60,14 @@ internal actual class PlatformDateFormat actual constructor(private val locale: // date picker headline and semantics are localized, // year picker is transformed to readable format + val pattern = when(skeleton){ DatePickerDefaults.YearAbbrMonthDaySkeleton -> { - return DateTimeFormatter - .ofLocalizedDate(FormatStyle.LONG) - .localizedBy(locale) + return dateFormatter .format(Instant.ofEpochMilli(utcTimeMillis).atOffset(ZoneOffset.UTC)) } DatePickerDefaults.YearMonthWeekdayDaySkeleton -> { - return DateTimeFormatter - .ofLocalizedDate(FormatStyle.FULL) - .localizedBy(locale) + return dateFormatter .format(Instant.ofEpochMilli(utcTimeMillis).atOffset(ZoneOffset.UTC)) } DatePickerDefaults.YearMonthSkeleton -> "MMMM yyyy" From 0f6be38517c12b3e1c83b5366259eb19ec2b9bf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=96=D0=B8=D1=80=D0=BA=D0=B5=D0=B2=D0=B8=D1=87?= Date: Thu, 29 Feb 2024 21:53:32 +0300 Subject: [PATCH 3/4] rollback extract formatter --- .../material3/PlatformDateFormat.desktop.kt | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/PlatformDateFormat.desktop.kt b/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/PlatformDateFormat.desktop.kt index 3b82bcd68031b..f6c640c43a466 100644 --- a/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/PlatformDateFormat.desktop.kt +++ b/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/PlatformDateFormat.desktop.kt @@ -33,12 +33,6 @@ internal actual class PlatformDateFormat actual constructor(private val locale: actual val firstDayOfWeek: Int get() = delegate.firstDayOfWeek - private val dateFormatter by lazy { - DateTimeFormatter - .ofLocalizedDate(FormatStyle.LONG) - .localizedBy(locale) - } - actual fun formatWithPattern( utcTimeMillis: Long, pattern: String, @@ -63,11 +57,15 @@ internal actual class PlatformDateFormat actual constructor(private val locale: val pattern = when(skeleton){ DatePickerDefaults.YearAbbrMonthDaySkeleton -> { - return dateFormatter + return DateTimeFormatter + .ofLocalizedDate(FormatStyle.LONG) + .localizedBy(locale) .format(Instant.ofEpochMilli(utcTimeMillis).atOffset(ZoneOffset.UTC)) } DatePickerDefaults.YearMonthWeekdayDaySkeleton -> { - return dateFormatter + return DateTimeFormatter + .ofLocalizedDate(FormatStyle.FULL) + .localizedBy(locale) .format(Instant.ofEpochMilli(utcTimeMillis).atOffset(ZoneOffset.UTC)) } DatePickerDefaults.YearMonthSkeleton -> "MMMM yyyy" From 61c5a87bf1cd2061c207f2808732fd468ff23c95 Mon Sep 17 00:00:00 2001 From: Alexander Zhirkevich Date: Mon, 4 Mar 2024 17:11:18 +0300 Subject: [PATCH 4/4] Update PlatformDateFormat.desktop.kt --- .../compose/material3/PlatformDateFormat.desktop.kt | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/PlatformDateFormat.desktop.kt b/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/PlatformDateFormat.desktop.kt index f6c640c43a466..8698011064990 100644 --- a/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/PlatformDateFormat.desktop.kt +++ b/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/PlatformDateFormat.desktop.kt @@ -45,20 +45,16 @@ internal actual class PlatformDateFormat actual constructor(private val locale: skeleton: String ): String { // Note: there is no equivalent in Java for Android's DateFormat.getBestDateTimePattern. - // The JDK SimpleDateFormat expects a pattern, so the results will be "2023Jan7", + // The JDK SimpleDateFormat expects a pattern, so the results for unrecognized skeletons will be "2023Jan7", // "2023January", etc. in case a skeleton holds an actual ICU skeleton and not a pattern. // TODO: support ICU skeleton on JVM // Maybe it will be supported in kotlinx.datetime in the future. - // See https://github.com/Kotlin/kotlinx-datetime/pull/251 - - // date picker headline and semantics are localized, - // year picker is transformed to readable format val pattern = when(skeleton){ DatePickerDefaults.YearAbbrMonthDaySkeleton -> { return DateTimeFormatter - .ofLocalizedDate(FormatStyle.LONG) + .ofLocalizedDate(FormatStyle.MEDIUM) .localizedBy(locale) .format(Instant.ofEpochMilli(utcTimeMillis).atOffset(ZoneOffset.UTC)) } @@ -68,7 +64,7 @@ internal actual class PlatformDateFormat actual constructor(private val locale: .localizedBy(locale) .format(Instant.ofEpochMilli(utcTimeMillis).atOffset(ZoneOffset.UTC)) } - DatePickerDefaults.YearMonthSkeleton -> "MMMM yyyy" + DatePickerDefaults.YearMonthSkeleton -> "LLLL yyyy" // L is a pattern for standalone month (without day) else -> skeleton } return formatWithPattern(utcTimeMillis, pattern)