1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.core.i18n 18 19 import android.os.Build 20 import androidx.annotation.RequiresApi 21 import java.text.DateFormat 22 import java.text.FieldPosition 23 import java.util.Calendar 24 import java.util.Locale 25 26 internal interface IDateTimeFormatterImpl { formatnull27 fun format(calendar: Calendar): String 28 } 29 30 internal class DateTimeFormatterImplAndroid(skeleton: String, locale: Locale) : 31 IDateTimeFormatterImpl { 32 33 private val sdf = 34 java.text.SimpleDateFormat( 35 android.text.format.DateFormat.getBestDateTimePattern(locale, skeleton), 36 locale 37 ) 38 39 override fun format(calendar: Calendar): String { 40 return sdf.format(calendar.time) 41 } 42 } 43 44 // ICU4J will give better results, so we use it if we can. 45 // And android.text.format.DateFormat.getBestDateTimePattern has a bug in API 26 and 27. 46 // For some skeletons it returns "b" instead of "a" in patterns (the am/pm). 47 // That is invalid, and throws when used to build the SimpleDateFormat 48 // Using ICU avoids that. 49 // Should also be faster, as the Android used JNI. 50 @RequiresApi(Build.VERSION_CODES.N) 51 internal class DateTimeFormatterImplIcu(skeleton: String, private var locale: Locale) : 52 IDateTimeFormatterImpl { 53 54 private val sdf = android.icu.text.DateFormat.getInstanceForSkeleton(skeleton, locale) 55 formatnull56 override fun format(calendar: Calendar): String { 57 val result = StringBuffer() 58 val tz = android.icu.util.TimeZone.getTimeZone(calendar.timeZone.id) 59 val ucal = android.icu.util.Calendar.getInstance(tz, locale) 60 sdf.calendar = ucal 61 val fp = FieldPosition(0) 62 sdf.format(calendar.timeInMillis, result, fp) 63 return result.toString() 64 } 65 } 66 67 internal class DateTimeFormatterImplJdkStyle(dateStyle: Int, timeStyle: Int, locale: Locale) : 68 IDateTimeFormatterImpl { 69 70 private val sdf = 71 if (dateStyle == -1) { 72 if (timeStyle == -1) { 73 DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, locale) 74 } else { 75 DateFormat.getTimeInstance(timeStyle, locale) 76 } 77 } else { 78 if (timeStyle == -1) { 79 DateFormat.getDateInstance(dateStyle, locale) 80 } else { 81 DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale) 82 } 83 } 84 formatnull85 override fun format(calendar: Calendar): String { 86 return sdf.format(calendar.time) 87 } 88 } 89