Loading core/java/android/text/format/TimeFormatter.java +59 −78 Original line number Diff line number Diff line Loading @@ -22,8 +22,7 @@ package android.text.format; import android.content.res.Resources; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.nio.CharBuffer; import java.util.Formatter; import java.util.Locale; import java.util.TimeZone; Loading @@ -31,15 +30,13 @@ import libcore.icu.LocaleData; import libcore.util.ZoneInfo; /** * Formatting logic for {@link Time}. Contains a port of Bionic's broken strftime_tz to Java. The * main issue with this implementation is the treatment of characters as ASCII, despite returning * localized (UTF-16) strings from the LocaleData. * Formatting logic for {@link Time}. Contains a port of Bionic's broken strftime_tz to Java. * * <p>This class is not thread safe. */ class TimeFormatter { // An arbitrary value outside the range representable by a byte / ASCII character code. private static final int FORCE_LOWER_CASE = 0x100; // An arbitrary value outside the range representable by a char. private static final int FORCE_LOWER_CASE = -1; private static final int SECSPERMIN = 60; private static final int MINSPERHOUR = 60; Loading @@ -62,10 +59,9 @@ class TimeFormatter { private final String dateTimeFormat; private final String timeOnlyFormat; private final String dateOnlyFormat; private final Locale locale; private StringBuilder outputBuilder; private Formatter outputFormatter; private Formatter numberFormatter; public TimeFormatter() { synchronized (TimeFormatter.class) { Loading @@ -84,7 +80,6 @@ class TimeFormatter { this.dateTimeFormat = sDateTimeFormat; this.timeOnlyFormat = sTimeOnlyFormat; this.dateOnlyFormat = sDateOnlyFormat; this.locale = locale; localeData = sLocaleData; } } Loading @@ -97,19 +92,21 @@ class TimeFormatter { StringBuilder stringBuilder = new StringBuilder(); outputBuilder = stringBuilder; outputFormatter = new Formatter(stringBuilder, locale); // This uses the US locale because number localization is handled separately (see below) // and locale sensitive strings are output directly using outputBuilder. numberFormatter = new Formatter(stringBuilder, Locale.US); formatInternal(pattern, wallTime, zoneInfo); String result = stringBuilder.toString(); // This behavior is the source of a bug since some formats are defined as being // in ASCII. Generally localization is very broken. // in ASCII and not localized. if (localeData.zeroDigit != '0') { result = localizeDigits(result); } return result; } finally { outputBuilder = null; outputFormatter = null; numberFormatter = null; } } Loading @@ -132,38 +129,30 @@ class TimeFormatter { * {@link #outputBuilder}. */ private void formatInternal(String pattern, ZoneInfo.WallTime wallTime, ZoneInfo zoneInfo) { // Convert to ASCII bytes to be compatible with old implementation behavior. byte[] bytes = pattern.getBytes(StandardCharsets.US_ASCII); if (bytes.length == 0) { return; } ByteBuffer formatBuffer = ByteBuffer.wrap(bytes); CharBuffer formatBuffer = CharBuffer.wrap(pattern); while (formatBuffer.remaining() > 0) { boolean outputCurrentByte = true; char currentByteAsChar = convertToChar(formatBuffer.get(formatBuffer.position())); if (currentByteAsChar == '%') { outputCurrentByte = handleToken(formatBuffer, wallTime, zoneInfo); boolean outputCurrentChar = true; char currentChar = formatBuffer.get(formatBuffer.position()); if (currentChar == '%') { outputCurrentChar = handleToken(formatBuffer, wallTime, zoneInfo); } if (outputCurrentByte) { currentByteAsChar = convertToChar(formatBuffer.get(formatBuffer.position())); outputBuilder.append(currentByteAsChar); if (outputCurrentChar) { outputBuilder.append(formatBuffer.get(formatBuffer.position())); } formatBuffer.position(formatBuffer.position() + 1); } } private boolean handleToken(ByteBuffer formatBuffer, ZoneInfo.WallTime wallTime, private boolean handleToken(CharBuffer formatBuffer, ZoneInfo.WallTime wallTime, ZoneInfo zoneInfo) { // The byte at formatBuffer.position() is expected to be '%' at this point. // The char at formatBuffer.position() is expected to be '%' at this point. int modifier = 0; while (formatBuffer.remaining() > 1) { // Increment the position then get the new current byte. // Increment the position then get the new current char. formatBuffer.position(formatBuffer.position() + 1); char currentByteAsChar = convertToChar(formatBuffer.get(formatBuffer.position())); switch (currentByteAsChar) { char currentChar = formatBuffer.get(formatBuffer.position()); switch (currentChar) { case 'A': modifyAndAppend((wallTime.getWeekDay() < 0 || wallTime.getWeekDay() >= DAYSPERWEEK) Loading Loading @@ -206,7 +195,7 @@ class TimeFormatter { formatInternal("%m/%d/%y", wallTime, zoneInfo); return false; case 'd': outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), wallTime.getMonthDay()); return false; case 'E': Loading @@ -218,46 +207,46 @@ class TimeFormatter { case '0': case '^': case '#': modifier = currentByteAsChar; modifier = currentChar; continue; case 'e': outputFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"), numberFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"), wallTime.getMonthDay()); return false; case 'F': formatInternal("%Y-%m-%d", wallTime, zoneInfo); return false; case 'H': outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), wallTime.getHour()); return false; case 'I': int hour = (wallTime.getHour() % 12 != 0) ? (wallTime.getHour() % 12) : 12; outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), hour); numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), hour); return false; case 'j': int yearDay = wallTime.getYearDay() + 1; outputFormatter.format(getFormat(modifier, "%03d", "%3d", "%d", "%03d"), numberFormatter.format(getFormat(modifier, "%03d", "%3d", "%d", "%03d"), yearDay); return false; case 'k': outputFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"), numberFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"), wallTime.getHour()); return false; case 'l': int n2 = (wallTime.getHour() % 12 != 0) ? (wallTime.getHour() % 12) : 12; outputFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"), n2); numberFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"), n2); return false; case 'M': outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), wallTime.getMinute()); return false; case 'm': outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), wallTime.getMonth() + 1); return false; case 'n': modifyAndAppend("\n", modifier); outputBuilder.append('\n'); return false; case 'p': modifyAndAppend((wallTime.getHour() >= (HOURSPERDAY / 2)) ? localeData.amPm[1] Loading @@ -274,27 +263,27 @@ class TimeFormatter { formatInternal("%I:%M:%S %p", wallTime, zoneInfo); return false; case 'S': outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), wallTime.getSecond()); return false; case 's': int timeInSeconds = wallTime.mktime(zoneInfo); modifyAndAppend(Integer.toString(timeInSeconds), modifier); outputBuilder.append(Integer.toString(timeInSeconds)); return false; case 'T': formatInternal("%H:%M:%S", wallTime, zoneInfo); return false; case 't': modifyAndAppend("\t", modifier); outputBuilder.append('\t'); return false; case 'U': outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), (wallTime.getYearDay() + DAYSPERWEEK - wallTime.getWeekDay()) / DAYSPERWEEK); return false; case 'u': int day = (wallTime.getWeekDay() == 0) ? DAYSPERWEEK : wallTime.getWeekDay(); outputFormatter.format("%d", day); numberFormatter.format("%d", day); return false; case 'V': /* ISO 8601 week number */ case 'G': /* ISO 8601 year (four digits) */ Loading Loading @@ -326,9 +315,9 @@ class TimeFormatter { --year; yday += isLeap(year) ? DAYSPERLYEAR : DAYSPERNYEAR; } if (currentByteAsChar == 'V') { outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), w); } else if (currentByteAsChar == 'g') { if (currentChar == 'V') { numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), w); } else if (currentChar == 'g') { outputYear(year, false, true, modifier); } else { outputYear(year, true, true, modifier); Loading @@ -342,10 +331,10 @@ class TimeFormatter { int n = (wallTime.getYearDay() + DAYSPERWEEK - ( wallTime.getWeekDay() != 0 ? (wallTime.getWeekDay() - 1) : (DAYSPERWEEK - 1))) / DAYSPERWEEK; outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), n); numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), n); return false; case 'w': outputFormatter.format("%d", wallTime.getWeekDay()); numberFormatter.format("%d", wallTime.getWeekDay()); return false; case 'X': formatInternal(timeOnlyFormat, wallTime, zoneInfo); Loading @@ -371,17 +360,17 @@ class TimeFormatter { return false; } int diff = wallTime.getGmtOffset(); String sign; char sign; if (diff < 0) { sign = "-"; sign = '-'; diff = -diff; } else { sign = "+"; sign = '+'; } modifyAndAppend(sign, modifier); outputBuilder.append(sign); diff /= SECSPERMIN; diff = (diff / MINSPERHOUR) * 100 + (diff % MINSPERHOUR); outputFormatter.format(getFormat(modifier, "%04d", "%4d", "%d", "%04d"), diff); numberFormatter.format(getFormat(modifier, "%04d", "%4d", "%d", "%04d"), diff); return false; } case '+': Loading Loading @@ -422,7 +411,6 @@ class TimeFormatter { break; default: outputBuilder.append(str); } } Loading @@ -443,14 +431,14 @@ class TimeFormatter { } if (outputTop) { if (lead == 0 && trail < 0) { modifyAndAppend("-0", modifier); outputBuilder.append("-0"); } else { outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), lead); numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), lead); } } if (outputBottom) { int n = ((trail < 0) ? -trail : trail); outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), n); numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), n); } } Loading @@ -472,24 +460,24 @@ class TimeFormatter { } /** * A broken implementation of {@link Character#isUpperCase(char)} that assumes ASCII in order to * be compatible with the old native implementation. * A broken implementation of {@link Character#isUpperCase(char)} that assumes ASCII codes in * order to be compatible with the old native implementation. */ private static boolean brokenIsUpper(char toCheck) { return toCheck >= 'A' && toCheck <= 'Z'; } /** * A broken implementation of {@link Character#isLowerCase(char)} that assumes ASCII in order to * be compatible with the old native implementation. * A broken implementation of {@link Character#isLowerCase(char)} that assumes ASCII codes in * order to be compatible with the old native implementation. */ private static boolean brokenIsLower(char toCheck) { return toCheck >= 'a' && toCheck <= 'z'; } /** * A broken implementation of {@link Character#toLowerCase(char)} that assumes ASCII in order to * be compatible with the old native implementation. * A broken implementation of {@link Character#toLowerCase(char)} that assumes ASCII codes in * order to be compatible with the old native implementation. */ private static char brokenToLower(char input) { if (input >= 'A' && input <= 'Z') { Loading @@ -499,8 +487,8 @@ class TimeFormatter { } /** * A broken implementation of {@link Character#toUpperCase(char)} that assumes ASCII in order to * be compatible with the old native implementation. * A broken implementation of {@link Character#toUpperCase(char)} that assumes ASCII codes in * order to be compatible with the old native implementation. */ private static char brokenToUpper(char input) { if (input >= 'a' && input <= 'z') { Loading @@ -509,11 +497,4 @@ class TimeFormatter { return input; } /** * Safely convert a byte containing an ASCII character to a char, even for character codes * > 127. */ private static char convertToChar(byte b) { return (char) (b & 0xFF); } } Loading
core/java/android/text/format/TimeFormatter.java +59 −78 Original line number Diff line number Diff line Loading @@ -22,8 +22,7 @@ package android.text.format; import android.content.res.Resources; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.nio.CharBuffer; import java.util.Formatter; import java.util.Locale; import java.util.TimeZone; Loading @@ -31,15 +30,13 @@ import libcore.icu.LocaleData; import libcore.util.ZoneInfo; /** * Formatting logic for {@link Time}. Contains a port of Bionic's broken strftime_tz to Java. The * main issue with this implementation is the treatment of characters as ASCII, despite returning * localized (UTF-16) strings from the LocaleData. * Formatting logic for {@link Time}. Contains a port of Bionic's broken strftime_tz to Java. * * <p>This class is not thread safe. */ class TimeFormatter { // An arbitrary value outside the range representable by a byte / ASCII character code. private static final int FORCE_LOWER_CASE = 0x100; // An arbitrary value outside the range representable by a char. private static final int FORCE_LOWER_CASE = -1; private static final int SECSPERMIN = 60; private static final int MINSPERHOUR = 60; Loading @@ -62,10 +59,9 @@ class TimeFormatter { private final String dateTimeFormat; private final String timeOnlyFormat; private final String dateOnlyFormat; private final Locale locale; private StringBuilder outputBuilder; private Formatter outputFormatter; private Formatter numberFormatter; public TimeFormatter() { synchronized (TimeFormatter.class) { Loading @@ -84,7 +80,6 @@ class TimeFormatter { this.dateTimeFormat = sDateTimeFormat; this.timeOnlyFormat = sTimeOnlyFormat; this.dateOnlyFormat = sDateOnlyFormat; this.locale = locale; localeData = sLocaleData; } } Loading @@ -97,19 +92,21 @@ class TimeFormatter { StringBuilder stringBuilder = new StringBuilder(); outputBuilder = stringBuilder; outputFormatter = new Formatter(stringBuilder, locale); // This uses the US locale because number localization is handled separately (see below) // and locale sensitive strings are output directly using outputBuilder. numberFormatter = new Formatter(stringBuilder, Locale.US); formatInternal(pattern, wallTime, zoneInfo); String result = stringBuilder.toString(); // This behavior is the source of a bug since some formats are defined as being // in ASCII. Generally localization is very broken. // in ASCII and not localized. if (localeData.zeroDigit != '0') { result = localizeDigits(result); } return result; } finally { outputBuilder = null; outputFormatter = null; numberFormatter = null; } } Loading @@ -132,38 +129,30 @@ class TimeFormatter { * {@link #outputBuilder}. */ private void formatInternal(String pattern, ZoneInfo.WallTime wallTime, ZoneInfo zoneInfo) { // Convert to ASCII bytes to be compatible with old implementation behavior. byte[] bytes = pattern.getBytes(StandardCharsets.US_ASCII); if (bytes.length == 0) { return; } ByteBuffer formatBuffer = ByteBuffer.wrap(bytes); CharBuffer formatBuffer = CharBuffer.wrap(pattern); while (formatBuffer.remaining() > 0) { boolean outputCurrentByte = true; char currentByteAsChar = convertToChar(formatBuffer.get(formatBuffer.position())); if (currentByteAsChar == '%') { outputCurrentByte = handleToken(formatBuffer, wallTime, zoneInfo); boolean outputCurrentChar = true; char currentChar = formatBuffer.get(formatBuffer.position()); if (currentChar == '%') { outputCurrentChar = handleToken(formatBuffer, wallTime, zoneInfo); } if (outputCurrentByte) { currentByteAsChar = convertToChar(formatBuffer.get(formatBuffer.position())); outputBuilder.append(currentByteAsChar); if (outputCurrentChar) { outputBuilder.append(formatBuffer.get(formatBuffer.position())); } formatBuffer.position(formatBuffer.position() + 1); } } private boolean handleToken(ByteBuffer formatBuffer, ZoneInfo.WallTime wallTime, private boolean handleToken(CharBuffer formatBuffer, ZoneInfo.WallTime wallTime, ZoneInfo zoneInfo) { // The byte at formatBuffer.position() is expected to be '%' at this point. // The char at formatBuffer.position() is expected to be '%' at this point. int modifier = 0; while (formatBuffer.remaining() > 1) { // Increment the position then get the new current byte. // Increment the position then get the new current char. formatBuffer.position(formatBuffer.position() + 1); char currentByteAsChar = convertToChar(formatBuffer.get(formatBuffer.position())); switch (currentByteAsChar) { char currentChar = formatBuffer.get(formatBuffer.position()); switch (currentChar) { case 'A': modifyAndAppend((wallTime.getWeekDay() < 0 || wallTime.getWeekDay() >= DAYSPERWEEK) Loading Loading @@ -206,7 +195,7 @@ class TimeFormatter { formatInternal("%m/%d/%y", wallTime, zoneInfo); return false; case 'd': outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), wallTime.getMonthDay()); return false; case 'E': Loading @@ -218,46 +207,46 @@ class TimeFormatter { case '0': case '^': case '#': modifier = currentByteAsChar; modifier = currentChar; continue; case 'e': outputFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"), numberFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"), wallTime.getMonthDay()); return false; case 'F': formatInternal("%Y-%m-%d", wallTime, zoneInfo); return false; case 'H': outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), wallTime.getHour()); return false; case 'I': int hour = (wallTime.getHour() % 12 != 0) ? (wallTime.getHour() % 12) : 12; outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), hour); numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), hour); return false; case 'j': int yearDay = wallTime.getYearDay() + 1; outputFormatter.format(getFormat(modifier, "%03d", "%3d", "%d", "%03d"), numberFormatter.format(getFormat(modifier, "%03d", "%3d", "%d", "%03d"), yearDay); return false; case 'k': outputFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"), numberFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"), wallTime.getHour()); return false; case 'l': int n2 = (wallTime.getHour() % 12 != 0) ? (wallTime.getHour() % 12) : 12; outputFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"), n2); numberFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"), n2); return false; case 'M': outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), wallTime.getMinute()); return false; case 'm': outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), wallTime.getMonth() + 1); return false; case 'n': modifyAndAppend("\n", modifier); outputBuilder.append('\n'); return false; case 'p': modifyAndAppend((wallTime.getHour() >= (HOURSPERDAY / 2)) ? localeData.amPm[1] Loading @@ -274,27 +263,27 @@ class TimeFormatter { formatInternal("%I:%M:%S %p", wallTime, zoneInfo); return false; case 'S': outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), wallTime.getSecond()); return false; case 's': int timeInSeconds = wallTime.mktime(zoneInfo); modifyAndAppend(Integer.toString(timeInSeconds), modifier); outputBuilder.append(Integer.toString(timeInSeconds)); return false; case 'T': formatInternal("%H:%M:%S", wallTime, zoneInfo); return false; case 't': modifyAndAppend("\t", modifier); outputBuilder.append('\t'); return false; case 'U': outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), (wallTime.getYearDay() + DAYSPERWEEK - wallTime.getWeekDay()) / DAYSPERWEEK); return false; case 'u': int day = (wallTime.getWeekDay() == 0) ? DAYSPERWEEK : wallTime.getWeekDay(); outputFormatter.format("%d", day); numberFormatter.format("%d", day); return false; case 'V': /* ISO 8601 week number */ case 'G': /* ISO 8601 year (four digits) */ Loading Loading @@ -326,9 +315,9 @@ class TimeFormatter { --year; yday += isLeap(year) ? DAYSPERLYEAR : DAYSPERNYEAR; } if (currentByteAsChar == 'V') { outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), w); } else if (currentByteAsChar == 'g') { if (currentChar == 'V') { numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), w); } else if (currentChar == 'g') { outputYear(year, false, true, modifier); } else { outputYear(year, true, true, modifier); Loading @@ -342,10 +331,10 @@ class TimeFormatter { int n = (wallTime.getYearDay() + DAYSPERWEEK - ( wallTime.getWeekDay() != 0 ? (wallTime.getWeekDay() - 1) : (DAYSPERWEEK - 1))) / DAYSPERWEEK; outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), n); numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), n); return false; case 'w': outputFormatter.format("%d", wallTime.getWeekDay()); numberFormatter.format("%d", wallTime.getWeekDay()); return false; case 'X': formatInternal(timeOnlyFormat, wallTime, zoneInfo); Loading @@ -371,17 +360,17 @@ class TimeFormatter { return false; } int diff = wallTime.getGmtOffset(); String sign; char sign; if (diff < 0) { sign = "-"; sign = '-'; diff = -diff; } else { sign = "+"; sign = '+'; } modifyAndAppend(sign, modifier); outputBuilder.append(sign); diff /= SECSPERMIN; diff = (diff / MINSPERHOUR) * 100 + (diff % MINSPERHOUR); outputFormatter.format(getFormat(modifier, "%04d", "%4d", "%d", "%04d"), diff); numberFormatter.format(getFormat(modifier, "%04d", "%4d", "%d", "%04d"), diff); return false; } case '+': Loading Loading @@ -422,7 +411,6 @@ class TimeFormatter { break; default: outputBuilder.append(str); } } Loading @@ -443,14 +431,14 @@ class TimeFormatter { } if (outputTop) { if (lead == 0 && trail < 0) { modifyAndAppend("-0", modifier); outputBuilder.append("-0"); } else { outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), lead); numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), lead); } } if (outputBottom) { int n = ((trail < 0) ? -trail : trail); outputFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), n); numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), n); } } Loading @@ -472,24 +460,24 @@ class TimeFormatter { } /** * A broken implementation of {@link Character#isUpperCase(char)} that assumes ASCII in order to * be compatible with the old native implementation. * A broken implementation of {@link Character#isUpperCase(char)} that assumes ASCII codes in * order to be compatible with the old native implementation. */ private static boolean brokenIsUpper(char toCheck) { return toCheck >= 'A' && toCheck <= 'Z'; } /** * A broken implementation of {@link Character#isLowerCase(char)} that assumes ASCII in order to * be compatible with the old native implementation. * A broken implementation of {@link Character#isLowerCase(char)} that assumes ASCII codes in * order to be compatible with the old native implementation. */ private static boolean brokenIsLower(char toCheck) { return toCheck >= 'a' && toCheck <= 'z'; } /** * A broken implementation of {@link Character#toLowerCase(char)} that assumes ASCII in order to * be compatible with the old native implementation. * A broken implementation of {@link Character#toLowerCase(char)} that assumes ASCII codes in * order to be compatible with the old native implementation. */ private static char brokenToLower(char input) { if (input >= 'A' && input <= 'Z') { Loading @@ -499,8 +487,8 @@ class TimeFormatter { } /** * A broken implementation of {@link Character#toUpperCase(char)} that assumes ASCII in order to * be compatible with the old native implementation. * A broken implementation of {@link Character#toUpperCase(char)} that assumes ASCII codes in * order to be compatible with the old native implementation. */ private static char brokenToUpper(char input) { if (input >= 'a' && input <= 'z') { Loading @@ -509,11 +497,4 @@ class TimeFormatter { return input; } /** * Safely convert a byte containing an ASCII character to a char, even for character codes * > 127. */ private static char convertToChar(byte b) { return (char) (b & 0xFF); } }