am 2cb314eb: am e0cd3c19: Merge "Improve DateFormat.format."
* commit '2cb314ebc7bb6495a94f577dfb57f9e6c56033ef':
Improve DateFormat.format.
diff --git a/api/current.txt b/api/current.txt
index 5794453..385d9ac 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -22518,19 +22518,19 @@
method public static java.text.DateFormat getMediumDateFormat(android.content.Context);
method public static java.text.DateFormat getTimeFormat(android.content.Context);
method public static boolean is24HourFormat(android.content.Context);
- field public static final char AM_PM = 97; // 0x0061 'a'
- field public static final char CAPITAL_AM_PM = 65; // 0x0041 'A'
- field public static final char DATE = 100; // 0x0064 'd'
- field public static final char DAY = 69; // 0x0045 'E'
- field public static final char HOUR = 104; // 0x0068 'h'
- field public static final char HOUR_OF_DAY = 107; // 0x006b 'k'
- field public static final char MINUTE = 109; // 0x006d 'm'
- field public static final char MONTH = 77; // 0x004d 'M'
- field public static final char QUOTE = 39; // 0x0027 '\''
- field public static final char SECONDS = 115; // 0x0073 's'
- field public static final char STANDALONE_MONTH = 76; // 0x004c 'L'
- field public static final char TIME_ZONE = 122; // 0x007a 'z'
- field public static final char YEAR = 121; // 0x0079 'y'
+ field public static final deprecated char AM_PM = 97; // 0x0061 'a'
+ field public static final deprecated char CAPITAL_AM_PM = 65; // 0x0041 'A'
+ field public static final deprecated char DATE = 100; // 0x0064 'd'
+ field public static final deprecated char DAY = 69; // 0x0045 'E'
+ field public static final deprecated char HOUR = 104; // 0x0068 'h'
+ field public static final deprecated char HOUR_OF_DAY = 107; // 0x006b 'k'
+ field public static final deprecated char MINUTE = 109; // 0x006d 'm'
+ field public static final deprecated char MONTH = 77; // 0x004d 'M'
+ field public static final deprecated char QUOTE = 39; // 0x0027 '\''
+ field public static final deprecated char SECONDS = 115; // 0x0073 's'
+ field public static final deprecated char STANDALONE_MONTH = 76; // 0x004c 'L'
+ field public static final deprecated char TIME_ZONE = 122; // 0x007a 'z'
+ field public static final deprecated char YEAR = 121; // 0x0079 'y'
}
public class DateUtils {
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index 7e230ac..6d61a5c 100644
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -34,178 +34,72 @@
import libcore.icu.LocaleData;
/**
- Utility class for producing strings with formatted date/time.
-
- <p>
- Most callers should avoid supplying their own format strings to this
- class' {@code format} methods and rely on the correctly localized ones
- supplied by the system. This class' factory methods return
- appropriately-localized {@link java.text.DateFormat} instances, suitable
- for both formatting and parsing dates. For the canonical documentation
- of format strings, see {@link java.text.SimpleDateFormat}.
- </p>
- <p>
- The format methods in this class takes as inputs a format string and a representation of a date/time.
- The format string controls how the output is generated.
- This class only supports a subset of the full Unicode specification.
- Use {@link java.text.SimpleDateFormat} if you need more.
- Formatting characters may be repeated in order to get more detailed representations
- of that field. For instance, the format character 'M' is used to
- represent the month. Depending on how many times that character is repeated
- you get a different representation.
- </p>
- <p>
- For the month of September:<br/>
- M -> 9<br/>
- MM -> 09<br/>
- MMM -> Sep<br/>
- MMMM -> September
- </p>
- <p>
- The effects of the duplication vary depending on the nature of the field.
- See the notes on the individual field formatters for details. For purely numeric
- fields such as <code>HOUR</code> adding more copies of the designator will
- zero-pad the value to that number of characters.
- </p>
- <p>
- For 7 minutes past the hour:<br/>
- m -> 7<br/>
- mm -> 07<br/>
- mmm -> 007<br/>
- mmmm -> 0007
- </p>
- <p>
- Examples for April 6, 1970 at 3:23am:<br/>
- "MM/dd/yy h:mmaa" -> "04/06/70 3:23am"<br/>
- "MMM dd, yyyy h:mmaa" -> "Apr 6, 1970 3:23am"<br/>
- "MMMM dd, yyyy h:mmaa" -> "April 6, 1970 3:23am"<br/>
- "E, MMMM dd, yyyy h:mmaa" -> "Mon, April 6, 1970 3:23am&<br/>
- "EEEE, MMMM dd, yyyy h:mmaa" -> "Monday, April 6, 1970 3:23am"<br/>
- "'Noteworthy day: 'M/d/yy" -> "Noteworthy day: 4/6/70"
+ * Utility class for producing strings with formatted date/time.
+ *
+ * <p>Most callers should avoid supplying their own format strings to this
+ * class' {@code format} methods and rely on the correctly localized ones
+ * supplied by the system. This class' factory methods return
+ * appropriately-localized {@link java.text.DateFormat} instances, suitable
+ * for both formatting and parsing dates. For the canonical documentation
+ * of format strings, see {@link java.text.SimpleDateFormat}.
+ *
+ * <p>The format methods in this class implement a subset of Unicode
+ * <a href="http://www.unicode.org/reports/tr35/#Date_Format_Patterns">UTS #35</a> patterns.
+ * The subset supported by this class includes the following format characters:
+ * {@code acdEhkLMmsyz}. See {@link java.text.SimpleDateFormat} for more documentation
+ * about patterns, or if you need a more compete implementation.
*/
-
public class DateFormat {
- /**
- Text in the format string that should be copied verbatim rather that
- interpreted as formatting codes must be surrounded by the <code>QUOTE</code>
- character. If you need to embed a literal <code>QUOTE</code> character in
- the output text then use two in a row.
- */
+ /** @deprecated Use a literal {@code '} instead. */
+ @Deprecated
public static final char QUOTE = '\'';
-
- /**
- This designator indicates whether the <code>HOUR</code> field is before
- or after noon. The output is lower-case.
-
- Examples:
- a -> a or p
- aa -> am or pm
- */
+
+ /** @deprecated Use a literal {@code 'a'} instead. */
+ @Deprecated
public static final char AM_PM = 'a';
- /**
- This designator indicates whether the <code>HOUR</code> field is before
- or after noon. The output is capitalized.
-
- Examples:
- A -> A or P
- AA -> AM or PM
- */
+ /** @deprecated Use a literal {@code 'a'} instead; 'A' was always equivalent to 'a'. */
+ @Deprecated
public static final char CAPITAL_AM_PM = 'A';
- /**
- This designator indicates the day of the month.
-
- Examples for the 9th of the month:
- d -> 9
- dd -> 09
- */
+ /** @deprecated Use a literal {@code 'd'} instead. */
+ @Deprecated
public static final char DATE = 'd';
- /**
- This designator indicates the name of the day of the week.
-
- Examples for Sunday:
- E -> Sun
- EEEE -> Sunday
- */
+ /** @deprecated Use a literal {@code 'E'} instead. */
+ @Deprecated
public static final char DAY = 'E';
- /**
- This designator indicates the hour of the day in 12 hour format.
-
- Examples for 3pm:
- h -> 3
- hh -> 03
- */
+ /** @deprecated Use a literal {@code 'h'} instead. */
+ @Deprecated
public static final char HOUR = 'h';
- /**
- This designator indicates the hour of the day in 24 hour format.
-
- Example for 3pm:
- k -> 15
-
- Examples for midnight:
- k -> 0
- kk -> 00
- */
+ /** @deprecated Use a literal {@code 'k'} instead. */
+ @Deprecated
public static final char HOUR_OF_DAY = 'k';
- /**
- This designator indicates the minute of the hour.
-
- Examples for 7 minutes past the hour:
- m -> 7
- mm -> 07
- */
+ /** @deprecated Use a literal {@code 'm'} instead. */
+ @Deprecated
public static final char MINUTE = 'm';
- /**
- This designator indicates the month of the year. See also
- {@link #STANDALONE_MONTH}.
-
- Examples for September:
- M -> 9
- MM -> 09
- MMM -> Sep
- MMMM -> September
- */
+ /** @deprecated Use a literal {@code 'M'} instead. */
+ @Deprecated
public static final char MONTH = 'M';
- /**
- This designator indicates the standalone month of the year,
- necessary in some format strings in some languages. For
- example, Russian distinguishes between the "June" in
- "June" and that in "June 2010".
- */
+ /** @deprecated Use a literal {@code 'L'} instead. */
+ @Deprecated
public static final char STANDALONE_MONTH = 'L';
- /**
- This designator indicates the seconds of the minute.
-
- Examples for 7 seconds past the minute:
- s -> 7
- ss -> 07
- */
+ /** @deprecated Use a literal {@code 's'} instead. */
+ @Deprecated
public static final char SECONDS = 's';
- /**
- This designator indicates the offset of the timezone from GMT.
-
- Example for US/Pacific timezone:
- z -> -0800
- zz -> PST
- */
+ /** @deprecated Use a literal {@code 'z'} instead. */
+ @Deprecated
public static final char TIME_ZONE = 'z';
- /**
- This designator indicates the year.
-
- Examples for 2006
- y -> 06
- yyyy -> 2006
- */
+ /** @deprecated Use a literal {@code 'y'} instead. */
+ @Deprecated
public static final char YEAR = 'y';
@@ -233,8 +127,7 @@
}
java.text.DateFormat natural =
- java.text.DateFormat.getTimeInstance(
- java.text.DateFormat.LONG, locale);
+ java.text.DateFormat.getTimeInstance(java.text.DateFormat.LONG, locale);
if (natural instanceof SimpleDateFormat) {
SimpleDateFormat sdf = (SimpleDateFormat) natural;
@@ -273,7 +166,7 @@
}
/**
- * Returns a {@link java.text.DateFormat} object that can format the date
+ * Returns a {@link java.text.DateFormat} object that can format the date
* in short form (such as 12/31/1999) according
* to the current locale and the user's date-order preference.
* @param context the application context
@@ -342,10 +235,10 @@
value = context.getString(R.string.numeric_date_format);
return value;
}
-
+
/**
* Returns a {@link java.text.DateFormat} object that can format the date
- * in long form (such as December 31, 1999) for the current locale.
+ * in long form (such as {@code Monday, January 3, 2000}) for the current locale.
* @param context the application context
* @return the {@link java.text.DateFormat} object that formats the date in long form.
*/
@@ -355,7 +248,7 @@
/**
* Returns a {@link java.text.DateFormat} object that can format the date
- * in medium form (such as Dec. 31, 1999) for the current locale.
+ * in medium form (such as {@code Jan 3, 2000}) for the current locale.
* @param context the application context
* @return the {@link java.text.DateFormat} object that formats the date in long form.
*/
@@ -365,13 +258,13 @@
/**
* Gets the current date format stored as a char array. The array will contain
- * 3 elements ({@link #DATE}, {@link #MONTH}, and {@link #YEAR}) in the order
+ * 3 elements ({@link #DATE}, {@link #MONTH}, and {@link #YEAR}) in the order
* specified by the user's format preference. Note that this order is
* only appropriate for all-numeric dates; spelled-out (MEDIUM and LONG)
* dates will generally contain other punctuation, spaces, or words,
* not just the day, month, and year, and not necessarily in the same
* order returned here.
- */
+ */
public static char[] getDateFormatOrder(Context context) {
char[] order = new char[] {DATE, MONTH, YEAR};
String value = getDateFormatString(context);
@@ -401,7 +294,7 @@
}
return order;
}
-
+
private static String getDateFormatString(Context context) {
String value = Settings.System.getString(context.getContentResolver(),
Settings.System.DATE_FORMAT);
@@ -410,7 +303,7 @@
}
/**
- * Given a format string and a time in milliseconds since Jan 1, 1970 GMT, returns a
+ * Given a format string and a time in milliseconds since Jan 1, 1970 GMT, returns a
* CharSequence containing the requested date.
* @param inFormat the format string, as described in {@link android.text.format.DateFormat}
* @param inTimeInMillis in milliseconds since Jan 1, 1970 GMT
@@ -428,22 +321,20 @@
* @return a {@link CharSequence} containing the requested text
*/
public static CharSequence format(CharSequence inFormat, Date inDate) {
- Calendar c = new GregorianCalendar();
-
+ Calendar c = new GregorianCalendar();
c.setTime(inDate);
-
return format(inFormat, c);
}
/**
* Indicates whether the specified format string contains seconds.
- *
+ *
* Always returns false if the input format is null.
- *
+ *
* @param inFormat the format string, as described in {@link android.text.format.DateFormat}
- *
+ *
* @return true if the format string contains {@link #SECONDS}, false otherwise
- *
+ *
* @hide
*/
public static boolean hasSeconds(CharSequence inFormat) {
@@ -508,24 +399,23 @@
}
/**
- * Given a format string and a {@link java.util.Calendar} object, returns a CharSequence
+ * Given a format string and a {@link java.util.Calendar} object, returns a CharSequence
* containing the requested date.
* @param inFormat the format string, as described in {@link android.text.format.DateFormat}
* @param inDate the date to format
* @return a {@link CharSequence} containing the requested text
*/
public static CharSequence format(CharSequence inFormat, Calendar inDate) {
- SpannableStringBuilder s = new SpannableStringBuilder(inFormat);
- int c;
- int count;
+ SpannableStringBuilder s = new SpannableStringBuilder(inFormat);
+ int count;
+
+ LocaleData localeData = LocaleData.get(Locale.getDefault());
int len = inFormat.length();
for (int i = 0; i < len; i += count) {
- int temp;
-
count = 1;
- c = s.charAt(i);
+ int c = s.charAt(i);
if (c == QUOTE) {
count = appendQuotedText(s, i, len);
@@ -538,102 +428,89 @@
}
String replacement;
-
switch (c) {
- case AM_PM:
- replacement = DateUtils.getAMPMString(inDate.get(Calendar.AM_PM));
+ case 'A':
+ case 'a':
+ replacement = localeData.amPm[inDate.get(Calendar.AM_PM) - Calendar.AM];
break;
-
- case CAPITAL_AM_PM:
- //FIXME: this is the same as AM_PM? no capital?
- replacement = DateUtils.getAMPMString(inDate.get(Calendar.AM_PM));
- break;
-
- case DATE:
+ case 'd':
replacement = zeroPad(inDate.get(Calendar.DATE), count);
break;
-
- case DAY:
- temp = inDate.get(Calendar.DAY_OF_WEEK);
- replacement = DateUtils.getDayOfWeekString(temp,
- count < 4 ?
- DateUtils.LENGTH_MEDIUM :
- DateUtils.LENGTH_LONG);
+ case 'c':
+ case 'E':
+ replacement = getDayOfWeekString(localeData,
+ inDate.get(Calendar.DAY_OF_WEEK), count, c);
break;
-
- case HOUR:
- temp = inDate.get(Calendar.HOUR);
-
- if (0 == temp)
- temp = 12;
-
- replacement = zeroPad(temp, count);
+ case 'h':
+ int hour = inDate.get(Calendar.HOUR);
+ replacement = zeroPad(hour == 0 ? 24 : hour, count);
break;
-
- case HOUR_OF_DAY:
+ case 'k':
replacement = zeroPad(inDate.get(Calendar.HOUR_OF_DAY), count);
break;
-
- case MINUTE:
+ case 'L':
+ case 'M':
+ replacement = getMonthString(localeData,
+ inDate.get(Calendar.MONTH), count, c);
+ break;
+ case 'm':
replacement = zeroPad(inDate.get(Calendar.MINUTE), count);
break;
-
- case MONTH:
- case STANDALONE_MONTH:
- replacement = getMonthString(inDate, count, c);
- break;
-
- case SECONDS:
+ case 's':
replacement = zeroPad(inDate.get(Calendar.SECOND), count);
break;
-
- case TIME_ZONE:
+ case 'y':
+ replacement = getYearString(inDate.get(Calendar.YEAR), count);
+ break;
+ case 'z':
replacement = getTimeZoneString(inDate, count);
break;
-
- case YEAR:
- replacement = getYearString(inDate, count);
- break;
-
default:
replacement = null;
break;
}
-
+
if (replacement != null) {
s.replace(i, i + count, replacement);
count = replacement.length(); // CARE: count is used in the for loop above
len = s.length();
}
}
-
- if (inFormat instanceof Spanned)
+
+ if (inFormat instanceof Spanned) {
return new SpannedString(s);
- else
+ } else {
return s.toString();
+ }
}
-
- private static String getMonthString(Calendar inDate, int count, int kind) {
- boolean standalone = (kind == STANDALONE_MONTH);
- int month = inDate.get(Calendar.MONTH);
-
- if (count >= 4) {
- return standalone
- ? DateUtils.getStandaloneMonthString(month, DateUtils.LENGTH_LONG)
- : DateUtils.getMonthString(month, DateUtils.LENGTH_LONG);
+
+ private static String getDayOfWeekString(LocaleData ld, int day, int count, int kind) {
+ boolean standalone = (kind == 'c');
+ if (count == 5) {
+ return standalone ? ld.tinyStandAloneWeekdayNames[day] : ld.tinyWeekdayNames[day];
+ } else if (count == 4) {
+ return standalone ? ld.longStandAloneWeekdayNames[day] : ld.longWeekdayNames[day];
+ } else {
+ return standalone ? ld.shortStandAloneWeekdayNames[day] : ld.shortWeekdayNames[day];
+ }
+ }
+
+ private static String getMonthString(LocaleData ld, int month, int count, int kind) {
+ boolean standalone = (kind == 'L');
+ if (count == 5) {
+ return standalone ? ld.tinyStandAloneMonthNames[month] : ld.tinyMonthNames[month];
+ } else if (count == 4) {
+ return standalone ? ld.longStandAloneMonthNames[month] : ld.longMonthNames[month];
} else if (count == 3) {
- return standalone
- ? DateUtils.getStandaloneMonthString(month, DateUtils.LENGTH_MEDIUM)
- : DateUtils.getMonthString(month, DateUtils.LENGTH_MEDIUM);
+ return standalone ? ld.shortStandAloneMonthNames[month] : ld.shortMonthNames[month];
} else {
// Calendar.JANUARY == 0, so add 1 to month.
return zeroPad(month+1, count);
}
}
-
+
private static String getTimeZoneString(Calendar inDate, int count) {
TimeZone tz = inDate.getTimeZone();
-
if (count < 2) { // FIXME: shouldn't this be <= 2 ?
return formatZoneOffset(inDate.get(Calendar.DST_OFFSET) +
inDate.get(Calendar.ZONE_OFFSET),
@@ -662,13 +539,12 @@
tb.append(zeroPad(minutes, 2));
return tb.toString();
}
-
- private static String getYearString(Calendar inDate, int count) {
- int year = inDate.get(Calendar.YEAR);
+
+ private static String getYearString(int year, int count) {
return (count <= 2) ? zeroPad(year % 100, 2)
: String.format(Locale.getDefault(), "%d", year);
}
-
+
private static int appendQuotedText(SpannableStringBuilder s, int i, int len) {
if (i + 1 < len && s.charAt(i + 1) == QUOTE) {
s.delete(i, i + 1);
diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java
index 5a20ceb..08813df 100644
--- a/core/java/android/text/format/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -274,10 +274,6 @@
*/
@Deprecated
public static String getMonthString(int month, int abbrev) {
- // Note that here we use d.shortMonthNames for MEDIUM, SHORT and SHORTER.
- // This is a shortcut to not spam the translators with too many variations
- // of the same string. If we find that in a language the distinction
- // is necessary, we can can add more without changing this API.
LocaleData d = LocaleData.get(Locale.getDefault());
String[] names;
switch (abbrev) {
@@ -308,19 +304,14 @@
*/
@Deprecated
public static String getStandaloneMonthString(int month, int abbrev) {
- // Note that here we use d.shortMonthNames for MEDIUM, SHORT and SHORTER.
- // This is a shortcut to not spam the translators with too many variations
- // of the same string. If we find that in a language the distinction
- // is necessary, we can can add more without changing this API.
LocaleData d = LocaleData.get(Locale.getDefault());
String[] names;
switch (abbrev) {
- case LENGTH_LONG: names = d.longStandAloneMonthNames;
- break;
+ case LENGTH_LONG: names = d.longStandAloneMonthNames; break;
case LENGTH_MEDIUM: names = d.shortMonthNames; break;
case LENGTH_SHORT: names = d.shortMonthNames; break;
case LENGTH_SHORTER: names = d.shortMonthNames; break;
- case LENGTH_SHORTEST: names = d.tinyMonthNames; break;
+ case LENGTH_SHORTEST: names = d.tinyStandAloneMonthNames; break;
default: names = d.shortMonthNames; break;
}
return names[month];