19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.text.format; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 209c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinekimport android.os.UserHandle; 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.SpannableStringBuilder; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.Spanned; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.SpannedString; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 264037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikasimport libcore.icu.ICU; 274037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikasimport libcore.icu.LocaleData; 284037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikas 294037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikasimport java.text.SimpleDateFormat; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Calendar; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Date; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.GregorianCalendar; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Locale; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.TimeZone; 354caba61ea0433099fc94e61221d02542c34e9e3aElliott Hughes 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 378326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * Utility class for producing strings with formatted date/time. 388326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * 398326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * <p>Most callers should avoid supplying their own format strings to this 408326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * class' {@code format} methods and rely on the correctly localized ones 418326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * supplied by the system. This class' factory methods return 428326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * appropriately-localized {@link java.text.DateFormat} instances, suitable 438326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * for both formatting and parsing dates. For the canonical documentation 448326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * of format strings, see {@link java.text.SimpleDateFormat}. 458326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * 46031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * <p>In cases where the system does not provide a suitable pattern, 47031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * this class offers the {@link #getBestDateTimePattern} method. 48031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * 49fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes * <p>The {@code format} methods in this class implement a subset of Unicode 508326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * <a href="http://www.unicode.org/reports/tr35/#Date_Format_Patterns">UTS #35</a> patterns. 51fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes * The subset currently supported by this class includes the following format characters: 52fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes * {@code acdEHhLKkLMmsyz}. Up to API level 17, only {@code adEhkMmszy} were supported. 53fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes * Note that this class incorrectly implements {@code k} as if it were {@code H} for backwards 54fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes * compatibility. 55fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes * 56fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes * <p>See {@link java.text.SimpleDateFormat} for more documentation 57fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes * about patterns, or if you need a more complete or correct implementation. 58fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes * Note that the non-{@code format} methods in this class are implemented by 59fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes * {@code SimpleDateFormat}. 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class DateFormat { 629d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath /** 639d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @deprecated Use a literal {@code '} instead. 649d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @removed 659d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath */ 668326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes @Deprecated 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final char QUOTE = '\''; 688326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes 699d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath /** 709d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @deprecated Use a literal {@code 'a'} instead. 719d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @removed 729d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath */ 738326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes @Deprecated 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final char AM_PM = 'a'; 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 769d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath /** 779d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @deprecated Use a literal {@code 'a'} instead; 'A' was always equivalent to 'a'. 789d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @removed 799d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath */ 808326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes @Deprecated 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final char CAPITAL_AM_PM = 'A'; 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 839d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath /** 849d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @deprecated Use a literal {@code 'd'} instead. 859d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @removed 869d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath */ 878326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes @Deprecated 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final char DATE = 'd'; 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 909d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath /** 919d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @deprecated Use a literal {@code 'E'} instead. 929d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @removed 939d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath */ 948326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes @Deprecated 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final char DAY = 'E'; 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 979d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath /** 989d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @deprecated Use a literal {@code 'h'} instead. 999d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @removed 1009d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath */ 1018326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes @Deprecated 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final char HOUR = 'h'; 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 104fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes /** 105fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes * @deprecated Use a literal {@code 'H'} (for compatibility with {@link SimpleDateFormat} 106fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes * and Unicode) or {@code 'k'} (for compatibility with Android releases up to and including 107fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes * Jelly Bean MR-1) instead. Note that the two are incompatible. 1089d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * 1099d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @removed 110fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes */ 1118326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes @Deprecated 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final char HOUR_OF_DAY = 'k'; 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1149d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath /** 1159d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @deprecated Use a literal {@code 'm'} instead. 1169d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @removed 1179d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath */ 1188326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes @Deprecated 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final char MINUTE = 'm'; 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1219d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath /** 1229d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @deprecated Use a literal {@code 'M'} instead. 1239d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @removed 1249d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath */ 1258326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes @Deprecated 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final char MONTH = 'M'; 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1289d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath /** 1299d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @deprecated Use a literal {@code 'L'} instead. 1309d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @removed 1319d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath */ 1328326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes @Deprecated 13334de3bc309fd9077cc1aa1e1af82652670fdb9dfElliott Hughes public static final char STANDALONE_MONTH = 'L'; 13434de3bc309fd9077cc1aa1e1af82652670fdb9dfElliott Hughes 1359d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath /** 1369d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @deprecated Use a literal {@code 's'} instead. 1379d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @removed 1389d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath */ 1398326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes @Deprecated 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final char SECONDS = 's'; 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1429d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath /** 1439d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @deprecated Use a literal {@code 'z'} instead. 1449d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @removed 1459d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath */ 1468326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes @Deprecated 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final char TIME_ZONE = 'z'; 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1499d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath /** 1509d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @deprecated Use a literal {@code 'y'} instead. 1519d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * @removed 1529d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath */ 1538326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes @Deprecated 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final char YEAR = 'y'; 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final Object sLocaleLock = new Object(); 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static Locale sIs24HourLocale; 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static boolean sIs24Hour; 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns true if user preference is set to 24-hour format. 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param context the context to use for the content resolver 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if 24 hour time format is selected, false otherwise. 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static boolean is24HourFormat(Context context) { 1689c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek return is24HourFormat(context, UserHandle.myUserId()); 1699c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek } 1709c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek 1719c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek /** 1729c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek * Returns true if user preference with the given user handle is set to 24-hour format. 1739c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek * @param context the context to use for the content resolver 1749c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek * @param userHandle the user handle of the user to query. 1759c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek * @return true if 24 hour time format is selected, false otherwise. 1769c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek * 1779c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek * @hide 1789c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek */ 1799c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek public static boolean is24HourFormat(Context context, int userHandle) { 1809c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek String value = Settings.System.getStringForUser(context.getContentResolver(), 1819c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek Settings.System.TIME_12_24, userHandle); 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (value == null) { 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Locale locale = context.getResources().getConfiguration().locale; 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (sLocaleLock) { 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sIs24HourLocale != null && sIs24HourLocale.equals(locale)) { 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return sIs24Hour; 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project java.text.DateFormat natural = 1939c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek java.text.DateFormat.getTimeInstance(java.text.DateFormat.LONG, locale); 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (natural instanceof SimpleDateFormat) { 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SimpleDateFormat sdf = (SimpleDateFormat) natural; 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String pattern = sdf.toPattern(); 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (pattern.indexOf('H') >= 0) { 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project value = "24"; 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project value = "12"; 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project value = "12"; 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (sLocaleLock) { 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sIs24HourLocale = locale; 2103d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy sIs24Hour = value.equals("24"); 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2123d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy 2133d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy return sIs24Hour; 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2163d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy return value.equals("24"); 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 220031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * Returns the best possible localized form of the given skeleton for the given 221031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * locale. A skeleton is similar to, and uses the same format characters as, a Unicode 222031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * <a href="http://www.unicode.org/reports/tr35/#Date_Format_Patterns">UTS #35</a> 223031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * pattern. 224031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * 225031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * <p>One difference is that order is irrelevant. For example, "MMMMd" will return 226031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * "MMMM d" in the {@code en_US} locale, but "d. MMMM" in the {@code de_CH} locale. 227031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * 228031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * <p>Note also in that second example that the necessary punctuation for German was 229031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * added. For the same input in {@code es_ES}, we'd have even more extra text: 230031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * "d 'de' MMMM". 231031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * 232031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * <p>This method will automatically correct for grammatical necessity. Given the 233031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * same "MMMMd" input, this method will return "d LLLL" in the {@code fa_IR} locale, 234031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * where stand-alone months are necessary. Lengths are preserved where meaningful, 235031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * so "Md" would give a different result to "MMMd", say, except in a locale such as 236031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * {@code ja_JP} where there is only one length of month. 237031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * 238031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * <p>This method will only return patterns that are in CLDR, and is useful whenever 239031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * you know what elements you want in your format string but don't want to make your 240031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * code specific to any one locale. 241031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * 242031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * @param locale the locale into which the skeleton should be localized 243031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * @param skeleton a skeleton as described above 244031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * @return a string pattern suitable for use with {@link java.text.SimpleDateFormat}. 245031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes */ 246031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes public static String getBestDateTimePattern(Locale locale, String skeleton) { 2472c9d2005ecd592fd5b038a6379b5f174d9e65121Narayan Kamath return ICU.getBestDateTimePattern(skeleton, locale); 248031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes } 249031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes 250031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes /** 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns a {@link java.text.DateFormat} object that can format the time according 252af0e7a7394bf1e2596c46f81c3b0302a56daab96Eric Fischer * to the current locale and the user's 12-/24-hour clock preference. 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param context the application context 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the {@link java.text.DateFormat} object that properly formats the time. 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2563d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy public static java.text.DateFormat getTimeFormat(Context context) { 257cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes return new java.text.SimpleDateFormat(getTimeFormatString(context)); 258cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes } 259cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes 260cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes /** 261cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes * Returns a String pattern that can be used to format the time according 262cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes * to the current locale and the user's 12-/24-hour clock preference. 263cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes * @param context the application context 264cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes * @hide 265cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes */ 266cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes public static String getTimeFormatString(Context context) { 2679c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek return getTimeFormatString(context, UserHandle.myUserId()); 2689c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek } 2699c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek 2709c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek /** 2719c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek * Returns a String pattern that can be used to format the time according 2729c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek * to the current locale and the user's 12-/24-hour clock preference. 2739c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek * @param context the application context 2749c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek * @param userHandle the user handle of the user to query the format for 2759c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek * @hide 2769c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek */ 2779c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek public static String getTimeFormatString(Context context, int userHandle) { 2784caba61ea0433099fc94e61221d02542c34e9e3aElliott Hughes LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale); 2790da89b76402816dade084166a97b1d352ae1f78bJorim Jaggi return is24HourFormat(context, userHandle) ? d.timeFormat_Hm : d.timeFormat_hm; 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2838326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * Returns a {@link java.text.DateFormat} object that can format the date 284f91f06a5991451e4af3cf99eba791cb3009810d2Narayan Kamath * in short form according to the current locale. 285f91f06a5991451e4af3cf99eba791cb3009810d2Narayan Kamath * 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param context the application context 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the {@link java.text.DateFormat} object that properly formats the date. 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2893d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy public static java.text.DateFormat getDateFormat(Context context) { 290f91f06a5991451e4af3cf99eba791cb3009810d2Narayan Kamath return java.text.DateFormat.getDateInstance(java.text.DateFormat.SHORT); 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2928326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns a {@link java.text.DateFormat} object that can format the date 2958326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * in long form (such as {@code Monday, January 3, 2000}) for the current locale. 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param context the application context 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the {@link java.text.DateFormat} object that formats the date in long form. 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2993d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy public static java.text.DateFormat getLongDateFormat(Context context) { 3005bd644caf73e76750feef1a82b8817d32f5367fcEric Fischer return java.text.DateFormat.getDateInstance(java.text.DateFormat.LONG); 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns a {@link java.text.DateFormat} object that can format the date 3058326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * in medium form (such as {@code Jan 3, 2000}) for the current locale. 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param context the application context 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the {@link java.text.DateFormat} object that formats the date in long form. 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3093d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy public static java.text.DateFormat getMediumDateFormat(Context context) { 3105bd644caf73e76750feef1a82b8817d32f5367fcEric Fischer return java.text.DateFormat.getDateInstance(java.text.DateFormat.MEDIUM); 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3149d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * Gets the current date format stored as a char array. Returns a 3 element 3159d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * array containing the day ({@code 'd'}), month ({@code 'M'}), and year ({@code 'y'})) 3169d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath * in the order specified by the user's format preference. Note that this order is 317edd6f9e688698da4f6ba9da5e56a5546f9162200Elliott Hughes * <i>only</i> appropriate for all-numeric dates; spelled-out (MEDIUM and LONG) 31803a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer * dates will generally contain other punctuation, spaces, or words, 31903a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer * not just the day, month, and year, and not necessarily in the same 32003a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer * order returned here. 3218326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes */ 3223d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy public static char[] getDateFormatOrder(Context context) { 323f91f06a5991451e4af3cf99eba791cb3009810d2Narayan Kamath return ICU.getDateFormatOrder(getDateFormatString()); 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3258326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes 326f91f06a5991451e4af3cf99eba791cb3009810d2Narayan Kamath private static String getDateFormatString() { 327f91f06a5991451e4af3cf99eba791cb3009810d2Narayan Kamath java.text.DateFormat df = java.text.DateFormat.getDateInstance(java.text.DateFormat.SHORT); 328f91f06a5991451e4af3cf99eba791cb3009810d2Narayan Kamath if (df instanceof SimpleDateFormat) { 329f91f06a5991451e4af3cf99eba791cb3009810d2Narayan Kamath return ((SimpleDateFormat) df).toPattern(); 330f91f06a5991451e4af3cf99eba791cb3009810d2Narayan Kamath } 33103a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer 332f91f06a5991451e4af3cf99eba791cb3009810d2Narayan Kamath throw new AssertionError("!(df instanceof SimpleDateFormat)"); 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3368326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * Given a format string and a time in milliseconds since Jan 1, 1970 GMT, returns a 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * CharSequence containing the requested date. 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param inFormat the format string, as described in {@link android.text.format.DateFormat} 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param inTimeInMillis in milliseconds since Jan 1, 1970 GMT 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return a {@link CharSequence} containing the requested text 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3423d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy public static CharSequence format(CharSequence inFormat, long inTimeInMillis) { 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return format(inFormat, new Date(inTimeInMillis)); 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Given a format string and a {@link java.util.Date} object, returns a CharSequence containing 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the requested date. 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param inFormat the format string, as described in {@link android.text.format.DateFormat} 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param inDate the date to format 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return a {@link CharSequence} containing the requested text 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3533d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy public static CharSequence format(CharSequence inFormat, Date inDate) { 3548326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes Calendar c = new GregorianCalendar(); 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c.setTime(inDate); 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return format(inFormat, c); 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3603d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * Indicates whether the specified format string contains seconds. 3618326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * 3623d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * Always returns false if the input format is null. 3638326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * 3643d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * @param inFormat the format string, as described in {@link android.text.format.DateFormat} 3658326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * 3663d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * @return true if the format string contains {@link #SECONDS}, false otherwise 3678326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * 3683d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * @hide 3693d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy */ 3703d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy public static boolean hasSeconds(CharSequence inFormat) { 37106c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey return hasDesignator(inFormat, SECONDS); 37206c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey } 37306c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey 37406c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey /** 37506c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey * Test if a format string contains the given designator. Always returns 37606c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey * {@code false} if the input format is {@code null}. 37706c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey * 37806c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey * @hide 37906c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey */ 38006c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey public static boolean hasDesignator(CharSequence inFormat, char designator) { 3813d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy if (inFormat == null) return false; 3823d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy 3833d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy final int length = inFormat.length(); 3843d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy 3853d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy int c; 3863d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy int count; 3873d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy 3883d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy for (int i = 0; i < length; i += count) { 3893d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy count = 1; 3903d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy c = inFormat.charAt(i); 3913d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy 3923d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy if (c == QUOTE) { 3933d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy count = skipQuotedText(inFormat, i, length); 39406c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey } else if (c == designator) { 3953d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy return true; 3963d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy } 3973d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy } 3983d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy 3993d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy return false; 4003d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy } 4013d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy 4023d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy private static int skipQuotedText(CharSequence s, int i, int len) { 4033d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy if (i + 1 < len && s.charAt(i + 1) == QUOTE) { 4043d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy return 2; 4053d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy } 4063d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy 4073d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy int count = 1; 4083d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy // skip leading quote 4093d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy i++; 4103d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy 4113d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy while (i < len) { 4123d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy char c = s.charAt(i); 4133d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy 4143d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy if (c == QUOTE) { 4153d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy count++; 4163d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy // QUOTEQUOTE -> QUOTE 4173d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy if (i + 1 < len && s.charAt(i + 1) == QUOTE) { 4183d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy i++; 4193d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy } else { 4203d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy break; 4213d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy } 4223d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy } else { 4233d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy i++; 4243d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy count++; 4253d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy } 4263d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy } 4273d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy 4283d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy return count; 4293d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy } 4303d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy 4313d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy /** 4328326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * Given a format string and a {@link java.util.Calendar} object, returns a CharSequence 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * containing the requested date. 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param inFormat the format string, as described in {@link android.text.format.DateFormat} 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param inDate the date to format 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return a {@link CharSequence} containing the requested text 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4383d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy public static CharSequence format(CharSequence inFormat, Calendar inDate) { 4398326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes SpannableStringBuilder s = new SpannableStringBuilder(inFormat); 4408326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes int count; 4418326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes 4428326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes LocaleData localeData = LocaleData.get(Locale.getDefault()); 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int len = inFormat.length(); 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < len; i += count) { 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project count = 1; 4488326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes int c = s.charAt(i); 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c == QUOTE) { 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project count = appendQuotedText(s, i, len); 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project len = s.length(); 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while ((i + count < len) && (s.charAt(i + count) == c)) { 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project count++; 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String replacement; 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (c) { 4628326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes case 'A': 4638326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes case 'a': 4648326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes replacement = localeData.amPm[inDate.get(Calendar.AM_PM) - Calendar.AM]; 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 4668326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes case 'd': 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project replacement = zeroPad(inDate.get(Calendar.DATE), count); 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 4698326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes case 'c': 4708326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes case 'E': 4718326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes replacement = getDayOfWeekString(localeData, 4728326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes inDate.get(Calendar.DAY_OF_WEEK), count, c); 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 4747a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes case 'K': // hour in am/pm (0-11) 4757a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes case 'h': // hour in am/pm (1-12) 4767a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes { 4777a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes int hour = inDate.get(Calendar.HOUR); 4787a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes if (c == 'h' && hour == 0) { 4797a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes hour = 12; 4807a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes } 4817a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes replacement = zeroPad(hour, count); 4827a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes } 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 4847a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes case 'H': // hour in day (0-23) 485fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes case 'k': // hour in day (1-24) [but see note below] 4867a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes { 4877a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes int hour = inDate.get(Calendar.HOUR_OF_DAY); 488fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes // Historically on Android 'k' was interpreted as 'H', which wasn't 489fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes // implemented, so pretty much all callers that want to format 24-hour 490fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes // times are abusing 'k'. http://b/8359981. 491fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes if (false && c == 'k' && hour == 0) { 4927a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes hour = 24; 4937a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes } 4947a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes replacement = zeroPad(hour, count); 4957a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes } 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 4978326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes case 'L': 4988326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes case 'M': 4998326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes replacement = getMonthString(localeData, 5008326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes inDate.get(Calendar.MONTH), count, c); 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 5028326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes case 'm': 5038326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes replacement = zeroPad(inDate.get(Calendar.MINUTE), count); 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 5058326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes case 's': 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project replacement = zeroPad(inDate.get(Calendar.SECOND), count); 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 5088326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes case 'y': 5098326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes replacement = getYearString(inDate.get(Calendar.YEAR), count); 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 5118326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes case 'z': 5128326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes replacement = getTimeZoneString(inDate, count); 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project replacement = null; 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5188326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (replacement != null) { 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project s.replace(i, i + count, replacement); 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project count = replacement.length(); // CARE: count is used in the for loop above 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project len = s.length(); 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5258326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes 5268326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes if (inFormat instanceof Spanned) { 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new SpannedString(s); 5288326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes } else { 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return s.toString(); 5308326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes } 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5328326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes 5338326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes private static String getDayOfWeekString(LocaleData ld, int day, int count, int kind) { 5348326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes boolean standalone = (kind == 'c'); 5358326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes if (count == 5) { 5368326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes return standalone ? ld.tinyStandAloneWeekdayNames[day] : ld.tinyWeekdayNames[day]; 5378326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes } else if (count == 4) { 5388326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes return standalone ? ld.longStandAloneWeekdayNames[day] : ld.longWeekdayNames[day]; 5398326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes } else { 5408326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes return standalone ? ld.shortStandAloneWeekdayNames[day] : ld.shortWeekdayNames[day]; 5418326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes } 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5438326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes 5448326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes private static String getMonthString(LocaleData ld, int month, int count, int kind) { 5458326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes boolean standalone = (kind == 'L'); 5468326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes if (count == 5) { 5478326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes return standalone ? ld.tinyStandAloneMonthNames[month] : ld.tinyMonthNames[month]; 5488326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes } else if (count == 4) { 5498326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes return standalone ? ld.longStandAloneMonthNames[month] : ld.longMonthNames[month]; 55034de3bc309fd9077cc1aa1e1af82652670fdb9dfElliott Hughes } else if (count == 3) { 5518326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes return standalone ? ld.shortStandAloneMonthNames[month] : ld.shortMonthNames[month]; 55234de3bc309fd9077cc1aa1e1af82652670fdb9dfElliott Hughes } else { 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Calendar.JANUARY == 0, so add 1 to month. 5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return zeroPad(month+1, count); 5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5578326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes 5583d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy private static String getTimeZoneString(Calendar inDate, int count) { 5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TimeZone tz = inDate.getTimeZone(); 5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (count < 2) { // FIXME: shouldn't this be <= 2 ? 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return formatZoneOffset(inDate.get(Calendar.DST_OFFSET) + 5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project inDate.get(Calendar.ZONE_OFFSET), 5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project count); 5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean dst = inDate.get(Calendar.DST_OFFSET) != 0; 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return tz.getDisplayName(dst, TimeZone.SHORT); 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5703d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy private static String formatZoneOffset(int offset, int count) { 5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project offset /= 1000; // milliseconds to seconds 5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder tb = new StringBuilder(); 5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (offset < 0) { 5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project tb.insert(0, "-"); 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project offset = -offset; 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project tb.insert(0, "+"); 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int hours = offset / 3600; 5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int minutes = (offset % 3600) / 60; 5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project tb.append(zeroPad(hours, 2)); 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project tb.append(zeroPad(minutes, 2)); 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return tb.toString(); 5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5888326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes 5898326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes private static String getYearString(int year, int count) { 59034de3bc309fd9077cc1aa1e1af82652670fdb9dfElliott Hughes return (count <= 2) ? zeroPad(year % 100, 2) 59134de3bc309fd9077cc1aa1e1af82652670fdb9dfElliott Hughes : String.format(Locale.getDefault(), "%d", year); 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5938326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes 5943d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy private static int appendQuotedText(SpannableStringBuilder s, int i, int len) { 5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (i + 1 < len && s.charAt(i + 1) == QUOTE) { 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project s.delete(i, i + 1); 5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 1; 5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = 0; 6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // delete leading quote 6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project s.delete(i, i + 1); 6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project len--; 6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (i < len) { 6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char c = s.charAt(i); 6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c == QUOTE) { 6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // QUOTEQUOTE -> QUOTE 6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (i + 1 < len && s.charAt(i + 1) == QUOTE) { 6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project s.delete(i, i + 1); 6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project len--; 6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project count++; 6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Closing QUOTE ends quoted text copying 6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project s.delete(i, i + 1); 6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project count++; 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return count; 6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6313d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy private static String zeroPad(int inValue, int inMinDigits) { 63234de3bc309fd9077cc1aa1e1af82652670fdb9dfElliott Hughes return String.format(Locale.getDefault(), "%0" + inMinDigits + "d", inValue); 6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 635