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