diff options
author | Elliott Hughes <enh@google.com> | 2010-01-13 23:14:56 -0800 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2010-01-14 12:50:53 -0800 |
commit | e1e5e8e60af12f145c4dd0395e30069665f97529 (patch) | |
tree | 191a722e9ccb999bf9eec8d162abc540f409fa8e /text/src | |
parent | b64c406bd2becd117d88cef3d90d84243d6016af (diff) | |
download | libcore-e1e5e8e60af12f145c4dd0395e30069665f97529.zip libcore-e1e5e8e60af12f145c4dd0395e30069665f97529.tar.gz libcore-e1e5e8e60af12f145c4dd0395e30069665f97529.tar.bz2 |
Fix Date.toString.
Date.toString was using the TimeZone id ("America/Los_Angeles") rather than
the time zone short name ("PDT" or "PST", depending on time of year). The
naive fix made things 5x slower, so I improved Resources.getDisplayTimeZone
so the fixed Date.toString is only 2x slower. This could be improved further
with a faster getDisplayTimeZone.
I hoped to replace the body of Date.toString with a call to SimpleDateFormat,
but that turns out to be 40x slower. This patch also optimizes SimpleDateFormat
to bring the gap down to 8x by using Resources.getDisplayTimeZone instead of
asking for all the strings.
(Note that these improvements refer to the hopefully common case of localized
strings for the default locale. If you have the misfortune to need strings for
other locales, the new code will be more like 600x faster. At 0.5s a call on
the fastest current hardware, I hope no-one's actually doing that.
Dalvik Explorer -- available on the Market -- needs to do it when generating
summary reports, and it is indeed ridiculously slow. It uses two
SimpleDateFormat objects per locale, so it takes 1s per locale, for about 60
locales. I've tested Dalvik Explorer with this patch, and it does fix that
pathological behavior.)
Also fix a bug I introduced in https://android-git.corp.google.com/g/36242 that
meant that our zone names String[][] contained incorrect values (accidentally
concatenating each successive value in a row), found by existing tests now we
use more of those values.
Also replace a couple of "new Integer" calls with Integer.valueOf for a modest
speedup.
Also factor out some duplication.
Bug: http://code.google.com/p/android/issues/detail?id=6013
Diffstat (limited to 'text/src')
-rw-r--r-- | text/src/main/java/java/text/DateFormatSymbols.java | 4 | ||||
-rw-r--r-- | text/src/main/java/java/text/SimpleDateFormat.java | 105 |
2 files changed, 58 insertions, 51 deletions
diff --git a/text/src/main/java/java/text/DateFormatSymbols.java b/text/src/main/java/java/text/DateFormatSymbols.java index 767a301..184cdcf 100644 --- a/text/src/main/java/java/text/DateFormatSymbols.java +++ b/text/src/main/java/java/text/DateFormatSymbols.java @@ -79,7 +79,10 @@ public class DateFormatSymbols implements Serializable, Cloneable { String[] ampms, eras, months, shortMonths, shortWeekdays, weekdays; + // Localized display names. String[][] zoneStrings; + // Has the user called setZoneStrings? + transient boolean customZoneStrings; // BEGIN android-removed // transient private com.ibm.icu4jni.text.DateFormatSymbols icuSymbols; @@ -474,5 +477,6 @@ public class DateFormatSymbols implements Serializable, Cloneable { */ public void setZoneStrings(String[][] data) { zoneStrings = Resources.clone2dStringArray(data); + customZoneStrings = true; } } diff --git a/text/src/main/java/java/text/SimpleDateFormat.java b/text/src/main/java/java/text/SimpleDateFormat.java index 01a4418..e2422ad 100644 --- a/text/src/main/java/java/text/SimpleDateFormat.java +++ b/text/src/main/java/java/text/SimpleDateFormat.java @@ -30,13 +30,13 @@ import java.util.Date; import java.util.GregorianCalendar; import java.util.Locale; // BEGIN android-added -import java.util.ResourceBundle; import java.util.SimpleTimeZone; import java.util.TimeZone; // END android-added import java.util.Vector; import com.ibm.icu4jni.util.LocaleData; +import com.ibm.icu4jni.util.Resources; import org.apache.harmony.text.internal.nls.Messages; /** @@ -894,7 +894,7 @@ public class SimpleDateFormat extends DateFormat { // BEGIN android-changed case (TIMEZONE_FIELD + 1): // Z dateFormatField = Field.TIME_ZONE; - appendTimeZone(buffer, count, false); + appendNumericTimeZone(buffer, false); break; // END android-changed } @@ -918,62 +918,65 @@ public class SimpleDateFormat extends DateFormat { } } - private void appendTimeZone(StringBuffer buffer, int count, - boolean generalTimezone) { - // cannot call TimeZone.getDisplayName() because it would not use - // the DateFormatSymbols of this SimpleDateFormat - - if (generalTimezone) { - String id = calendar.getTimeZone().getID(); - // BEGIN android-changed - String[][] zones = formatData.internalZoneStrings(); - // END android-changed - String[] zone = null; - for (String[] element : zones) { - if (id.equals(element[0])) { - zone = element; - break; - } - } - if (zone == null) { - int offset = calendar.get(Calendar.ZONE_OFFSET) - + calendar.get(Calendar.DST_OFFSET); - char sign = '+'; - if (offset < 0) { - sign = '-'; - offset = -offset; - } - buffer.append("GMT"); //$NON-NLS-1$ - buffer.append(sign); - appendNumber(buffer, 2, offset / 3600000); - buffer.append(':'); - appendNumber(buffer, 2, (offset % 3600000) / 60000); - } else { - int daylight = calendar.get(Calendar.DST_OFFSET) == 0 ? 0 : 2; - if (count < 4) { - buffer.append(zone[2 + daylight]); - } else { - buffer.append(zone[1 + daylight]); - } + /** + * Append a representation of the time zone of 'calendar' to 'buffer'. + * + * @param count the number of z or Z characters in the format string; "zzz" would be 3, + * for example. + * @param generalTimeZone true if we should use a display name ("PDT") if available; + * false implies that we should use RFC 822 format ("-0800") instead. This corresponds to 'z' + * versus 'Z' in the format string. + */ + private void appendTimeZone(StringBuffer buffer, int count, boolean generalTimeZone) { + // BEGIN android-changed: optimized. + if (generalTimeZone) { + TimeZone tz = calendar.getTimeZone(); + boolean daylight = (calendar.get(Calendar.DST_OFFSET) != 0); + int style = count < 4 ? TimeZone.SHORT : TimeZone.LONG; + if (!formatData.customZoneStrings) { + buffer.append(tz.getDisplayName(daylight, style, formatData.locale)); + return; } - } else { - int offset = calendar.get(Calendar.ZONE_OFFSET) - + calendar.get(Calendar.DST_OFFSET); - char sign = '+'; - if (offset < 0) { - sign = '-'; - offset = -offset; + // We can't call TimeZone.getDisplayName() because it would not use + // the custom DateFormatSymbols of this SimpleDateFormat. + String custom = Resources.lookupDisplayTimeZone(formatData.zoneStrings, tz.getID(), daylight, style); + if (custom != null) { + buffer.append(custom); + return; } - buffer.append(sign); - appendNumber(buffer, 2, offset / 3600000); - appendNumber(buffer, 2, (offset % 3600000) / 60000); } + // We didn't find what we were looking for, so default to a numeric time zone. + appendNumericTimeZone(buffer, generalTimeZone); + // END android-changed } + // BEGIN android-added: factored out duplication. + /** + * @param generalTimeZone "GMT-08:00" rather than "-0800". + */ + private void appendNumericTimeZone(StringBuffer buffer, boolean generalTimeZone) { + int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET); + char sign = '+'; + if (offset < 0) { + sign = '-'; + offset = -offset; + } + if (generalTimeZone) { + buffer.append("GMT"); + } + buffer.append(sign); + appendNumber(buffer, 2, offset / 3600000); + if (generalTimeZone) { + buffer.append(':'); + } + appendNumber(buffer, 2, (offset % 3600000) / 60000); + } + // END android-added + private void appendNumber(StringBuffer buffer, int count, int value) { int minimumIntegerDigits = numberFormat.getMinimumIntegerDigits(); numberFormat.setMinimumIntegerDigits(count); - numberFormat.format(new Integer(value), buffer, new FieldPosition(0)); + numberFormat.format(Integer.valueOf(value), buffer, new FieldPosition(0)); numberFormat.setMinimumIntegerDigits(minimumIntegerDigits); } @@ -1296,7 +1299,7 @@ public class SimpleDateFormat extends DateFormat { return null; } position.setIndex(index); - return new Integer(result); + return Integer.valueOf(result); } private int parseNumber(int max, String string, int offset, int field, |