1d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller/* 2d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller * Based on the UCB version of strftime.c with the copyright notice appearing below. 3d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller */ 4d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 5d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller/* 6d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller** Copyright (c) 1989 The Regents of the University of California. 7d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller** All rights reserved. 8d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller** 9d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller** Redistribution and use in source and binary forms are permitted 10d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller** provided that the above copyright notice and this paragraph are 11d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller** duplicated in all such forms and that any documentation, 12d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller** advertising materials, and other materials related to such 13d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller** distribution and use acknowledge that the software was developed 14d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller** by the University of California, Berkeley. The name of the 15d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller** University may not be used to endorse or promote products derived 16d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller** from this software without specific prior written permission. 17d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller** THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR 18d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller** IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 19d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller*/ 21d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fullerpackage android.text.format; 22d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 23d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fullerimport android.content.res.Resources; 24d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 25788cb18f652fca380acefdadce305415bc0602b0Neil Fullerimport java.nio.CharBuffer; 26d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fullerimport java.util.Formatter; 27d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fullerimport java.util.Locale; 28d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fullerimport java.util.TimeZone; 29d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fullerimport libcore.icu.LocaleData; 30d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fullerimport libcore.util.ZoneInfo; 31d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 32d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller/** 33788cb18f652fca380acefdadce305415bc0602b0Neil Fuller * Formatting logic for {@link Time}. Contains a port of Bionic's broken strftime_tz to Java. 34d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller * 35d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller * <p>This class is not thread safe. 36d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller */ 37d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fullerclass TimeFormatter { 38788cb18f652fca380acefdadce305415bc0602b0Neil Fuller // An arbitrary value outside the range representable by a char. 39788cb18f652fca380acefdadce305415bc0602b0Neil Fuller private static final int FORCE_LOWER_CASE = -1; 40d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 41d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static final int SECSPERMIN = 60; 42d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static final int MINSPERHOUR = 60; 43d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static final int DAYSPERWEEK = 7; 44d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static final int MONSPERYEAR = 12; 45d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static final int HOURSPERDAY = 24; 46d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static final int DAYSPERLYEAR = 366; 47d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static final int DAYSPERNYEAR = 365; 48d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 49d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller /** 50d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller * The Locale for which the cached LocaleData and formats have been loaded. 51d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller */ 52d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static Locale sLocale; 53d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static LocaleData sLocaleData; 54d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static String sTimeOnlyFormat; 55d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static String sDateOnlyFormat; 56d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static String sDateTimeFormat; 57d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 58d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private final LocaleData localeData; 59d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private final String dateTimeFormat; 60d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private final String timeOnlyFormat; 61d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private final String dateOnlyFormat; 62d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 63d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private StringBuilder outputBuilder; 64788cb18f652fca380acefdadce305415bc0602b0Neil Fuller private Formatter numberFormatter; 65d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 66d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller public TimeFormatter() { 67d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller synchronized (TimeFormatter.class) { 68d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller Locale locale = Locale.getDefault(); 69d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 70d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (sLocale == null || !(locale.equals(sLocale))) { 71d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller sLocale = locale; 72d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller sLocaleData = LocaleData.get(locale); 73d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 74d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller Resources r = Resources.getSystem(); 75d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller sTimeOnlyFormat = r.getString(com.android.internal.R.string.time_of_day); 76d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller sDateOnlyFormat = r.getString(com.android.internal.R.string.month_day_year); 77d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller sDateTimeFormat = r.getString(com.android.internal.R.string.date_and_time); 78d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 79d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 80d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller this.dateTimeFormat = sDateTimeFormat; 81d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller this.timeOnlyFormat = sTimeOnlyFormat; 82d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller this.dateOnlyFormat = sDateOnlyFormat; 83d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller localeData = sLocaleData; 84d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 85d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 86d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 87d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller /** 88d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller * Format the specified {@code wallTime} using {@code pattern}. The output is returned. 89d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller */ 90d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller public String format(String pattern, ZoneInfo.WallTime wallTime, ZoneInfo zoneInfo) { 91d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller try { 92d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller StringBuilder stringBuilder = new StringBuilder(); 93d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 94d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller outputBuilder = stringBuilder; 95788cb18f652fca380acefdadce305415bc0602b0Neil Fuller // This uses the US locale because number localization is handled separately (see below) 96788cb18f652fca380acefdadce305415bc0602b0Neil Fuller // and locale sensitive strings are output directly using outputBuilder. 97788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter = new Formatter(stringBuilder, Locale.US); 98d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 99d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatInternal(pattern, wallTime, zoneInfo); 100d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller String result = stringBuilder.toString(); 101d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller // This behavior is the source of a bug since some formats are defined as being 102788cb18f652fca380acefdadce305415bc0602b0Neil Fuller // in ASCII and not localized. 103d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (localeData.zeroDigit != '0') { 104d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller result = localizeDigits(result); 105d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 106d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return result; 107d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } finally { 108d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller outputBuilder = null; 109788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter = null; 110d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 111d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 112d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 113d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private String localizeDigits(String s) { 114d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int length = s.length(); 115d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int offsetToLocalizedDigits = localeData.zeroDigit - '0'; 116d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller StringBuilder result = new StringBuilder(length); 117d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller for (int i = 0; i < length; ++i) { 118d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller char ch = s.charAt(i); 119d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (ch >= '0' && ch <= '9') { 120d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller ch += offsetToLocalizedDigits; 121d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 122d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller result.append(ch); 123d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 124d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return result.toString(); 125d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 126d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 127d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller /** 128d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller * Format the specified {@code wallTime} using {@code pattern}. The output is written to 129d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller * {@link #outputBuilder}. 130d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller */ 131d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private void formatInternal(String pattern, ZoneInfo.WallTime wallTime, ZoneInfo zoneInfo) { 132788cb18f652fca380acefdadce305415bc0602b0Neil Fuller CharBuffer formatBuffer = CharBuffer.wrap(pattern); 133d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller while (formatBuffer.remaining() > 0) { 134788cb18f652fca380acefdadce305415bc0602b0Neil Fuller boolean outputCurrentChar = true; 135788cb18f652fca380acefdadce305415bc0602b0Neil Fuller char currentChar = formatBuffer.get(formatBuffer.position()); 136788cb18f652fca380acefdadce305415bc0602b0Neil Fuller if (currentChar == '%') { 137788cb18f652fca380acefdadce305415bc0602b0Neil Fuller outputCurrentChar = handleToken(formatBuffer, wallTime, zoneInfo); 138d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 139788cb18f652fca380acefdadce305415bc0602b0Neil Fuller if (outputCurrentChar) { 140788cb18f652fca380acefdadce305415bc0602b0Neil Fuller outputBuilder.append(formatBuffer.get(formatBuffer.position())); 141d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 142d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatBuffer.position(formatBuffer.position() + 1); 143d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 144d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 145d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 146788cb18f652fca380acefdadce305415bc0602b0Neil Fuller private boolean handleToken(CharBuffer formatBuffer, ZoneInfo.WallTime wallTime, 147d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller ZoneInfo zoneInfo) { 148d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 149788cb18f652fca380acefdadce305415bc0602b0Neil Fuller // The char at formatBuffer.position() is expected to be '%' at this point. 150d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int modifier = 0; 151d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller while (formatBuffer.remaining() > 1) { 152788cb18f652fca380acefdadce305415bc0602b0Neil Fuller // Increment the position then get the new current char. 153d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatBuffer.position(formatBuffer.position() + 1); 154788cb18f652fca380acefdadce305415bc0602b0Neil Fuller char currentChar = formatBuffer.get(formatBuffer.position()); 155788cb18f652fca380acefdadce305415bc0602b0Neil Fuller switch (currentChar) { 156d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'A': 157d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifyAndAppend((wallTime.getWeekDay() < 0 158d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller || wallTime.getWeekDay() >= DAYSPERWEEK) 159d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller ? "?" : localeData.longWeekdayNames[wallTime.getWeekDay() + 1], 160d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifier); 161d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 162d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'a': 163d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifyAndAppend((wallTime.getWeekDay() < 0 164d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller || wallTime.getWeekDay() >= DAYSPERWEEK) 165d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller ? "?" : localeData.shortWeekdayNames[wallTime.getWeekDay() + 1], 166d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifier); 167d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 168d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'B': 169d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (modifier == '-') { 170d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifyAndAppend((wallTime.getMonth() < 0 171d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller || wallTime.getMonth() >= MONSPERYEAR) 172d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller ? "?" 173d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller : localeData.longStandAloneMonthNames[wallTime.getMonth()], 174d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifier); 175d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } else { 176d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifyAndAppend((wallTime.getMonth() < 0 177d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller || wallTime.getMonth() >= MONSPERYEAR) 178d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller ? "?" : localeData.longMonthNames[wallTime.getMonth()], 179d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifier); 180d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 181d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 182d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'b': 183d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'h': 184d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifyAndAppend((wallTime.getMonth() < 0 || wallTime.getMonth() >= MONSPERYEAR) 185d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller ? "?" : localeData.shortMonthNames[wallTime.getMonth()], 186d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifier); 187d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 188d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'C': 189d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller outputYear(wallTime.getYear(), true, false, modifier); 190d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 191d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'c': 192d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatInternal(dateTimeFormat, wallTime, zoneInfo); 193d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 194d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'D': 195d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatInternal("%m/%d/%y", wallTime, zoneInfo); 196d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 197d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'd': 198788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), 199d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller wallTime.getMonthDay()); 200d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 201d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'E': 202d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'O': 203d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller // C99 locale modifiers are not supported. 204d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller continue; 205d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '_': 206d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '-': 207d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '0': 208d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '^': 209d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '#': 210788cb18f652fca380acefdadce305415bc0602b0Neil Fuller modifier = currentChar; 211d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller continue; 212d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'e': 213788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"), 214d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller wallTime.getMonthDay()); 215d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 216d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'F': 217d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatInternal("%Y-%m-%d", wallTime, zoneInfo); 218d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 219d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'H': 220788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), 221d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller wallTime.getHour()); 222d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 223d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'I': 224d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int hour = (wallTime.getHour() % 12 != 0) ? (wallTime.getHour() % 12) : 12; 225788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), hour); 226d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 227d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'j': 228d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int yearDay = wallTime.getYearDay() + 1; 229788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%03d", "%3d", "%d", "%03d"), 230d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller yearDay); 231d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 232d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'k': 233788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"), 234d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller wallTime.getHour()); 235d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 236d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'l': 237d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int n2 = (wallTime.getHour() % 12 != 0) ? (wallTime.getHour() % 12) : 12; 238788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"), n2); 239d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 240d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'M': 241788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), 242d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller wallTime.getMinute()); 243d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 244d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'm': 245788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), 246d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller wallTime.getMonth() + 1); 247d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 248d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'n': 249788cb18f652fca380acefdadce305415bc0602b0Neil Fuller outputBuilder.append('\n'); 250d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 251d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'p': 252d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifyAndAppend((wallTime.getHour() >= (HOURSPERDAY / 2)) ? localeData.amPm[1] 253d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller : localeData.amPm[0], modifier); 254d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 255d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'P': 256d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifyAndAppend((wallTime.getHour() >= (HOURSPERDAY / 2)) ? localeData.amPm[1] 257d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller : localeData.amPm[0], FORCE_LOWER_CASE); 258d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 259d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'R': 260d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatInternal("%H:%M", wallTime, zoneInfo); 261d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 262d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'r': 263d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatInternal("%I:%M:%S %p", wallTime, zoneInfo); 264d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 265d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'S': 266788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), 267d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller wallTime.getSecond()); 268d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 269d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 's': 270d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int timeInSeconds = wallTime.mktime(zoneInfo); 271788cb18f652fca380acefdadce305415bc0602b0Neil Fuller outputBuilder.append(Integer.toString(timeInSeconds)); 272d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 273d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'T': 274d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatInternal("%H:%M:%S", wallTime, zoneInfo); 275d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 276d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 't': 277788cb18f652fca380acefdadce305415bc0602b0Neil Fuller outputBuilder.append('\t'); 278d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 279d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'U': 280788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), 281d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller (wallTime.getYearDay() + DAYSPERWEEK - wallTime.getWeekDay()) 282d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller / DAYSPERWEEK); 283d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 284d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'u': 285d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int day = (wallTime.getWeekDay() == 0) ? DAYSPERWEEK : wallTime.getWeekDay(); 286788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format("%d", day); 287d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 288d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'V': /* ISO 8601 week number */ 289d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'G': /* ISO 8601 year (four digits) */ 290d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'g': /* ISO 8601 year (two digits) */ 291d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller { 292d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int year = wallTime.getYear(); 293d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int yday = wallTime.getYearDay(); 294d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int wday = wallTime.getWeekDay(); 295d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int w; 296d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller while (true) { 297d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int len = isLeap(year) ? DAYSPERLYEAR : DAYSPERNYEAR; 298d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller // What yday (-3 ... 3) does the ISO year begin on? 299d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int bot = ((yday + 11 - wday) % DAYSPERWEEK) - 3; 300d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller // What yday does the NEXT ISO year begin on? 301d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int top = bot - (len % DAYSPERWEEK); 302d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (top < -3) { 303d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller top += DAYSPERWEEK; 304d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 305d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller top += len; 306d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (yday >= top) { 307d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller ++year; 308d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller w = 1; 309d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller break; 310d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 311d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (yday >= bot) { 312d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller w = 1 + ((yday - bot) / DAYSPERWEEK); 313d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller break; 314d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 315d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller --year; 316d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller yday += isLeap(year) ? DAYSPERLYEAR : DAYSPERNYEAR; 317d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 318788cb18f652fca380acefdadce305415bc0602b0Neil Fuller if (currentChar == 'V') { 319788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), w); 320788cb18f652fca380acefdadce305415bc0602b0Neil Fuller } else if (currentChar == 'g') { 321d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller outputYear(year, false, true, modifier); 322d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } else { 323d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller outputYear(year, true, true, modifier); 324d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 325d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 326d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 327d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'v': 328d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatInternal("%e-%b-%Y", wallTime, zoneInfo); 329d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 330d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'W': 331d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int n = (wallTime.getYearDay() + DAYSPERWEEK - ( 332d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller wallTime.getWeekDay() != 0 ? (wallTime.getWeekDay() - 1) 333d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller : (DAYSPERWEEK - 1))) / DAYSPERWEEK; 334788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), n); 335d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 336d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'w': 337788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format("%d", wallTime.getWeekDay()); 338d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 339d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'X': 340d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatInternal(timeOnlyFormat, wallTime, zoneInfo); 341d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 342d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'x': 343d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatInternal(dateOnlyFormat, wallTime, zoneInfo); 344d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 345d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'y': 346d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller outputYear(wallTime.getYear(), false, true, modifier); 347d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 348d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'Y': 349d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller outputYear(wallTime.getYear(), true, true, modifier); 350d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 351d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'Z': 352d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (wallTime.getIsDst() < 0) { 353d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 354d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 355d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller boolean isDst = wallTime.getIsDst() != 0; 356d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifyAndAppend(zoneInfo.getDisplayName(isDst, TimeZone.SHORT), modifier); 357d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 358d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'z': { 359d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (wallTime.getIsDst() < 0) { 360d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 361d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 362d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int diff = wallTime.getGmtOffset(); 363788cb18f652fca380acefdadce305415bc0602b0Neil Fuller char sign; 364d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (diff < 0) { 365788cb18f652fca380acefdadce305415bc0602b0Neil Fuller sign = '-'; 366d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller diff = -diff; 367d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } else { 368788cb18f652fca380acefdadce305415bc0602b0Neil Fuller sign = '+'; 369d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 370788cb18f652fca380acefdadce305415bc0602b0Neil Fuller outputBuilder.append(sign); 371d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller diff /= SECSPERMIN; 372d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller diff = (diff / MINSPERHOUR) * 100 + (diff % MINSPERHOUR); 373788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%04d", "%4d", "%d", "%04d"), diff); 374d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 375d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 376d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '+': 377d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatInternal("%a %b %e %H:%M:%S %Z %Y", wallTime, zoneInfo); 378d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 379d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '%': 380d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller // If conversion char is undefined, behavior is undefined. Print out the 381d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller // character itself. 382d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller default: 383d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return true; 384d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 385d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 386d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return true; 387d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 388d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 389d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private void modifyAndAppend(CharSequence str, int modifier) { 390d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller switch (modifier) { 391d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case FORCE_LOWER_CASE: 392d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller for (int i = 0; i < str.length(); i++) { 393d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller outputBuilder.append(brokenToLower(str.charAt(i))); 394d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 395d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller break; 396d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '^': 397d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller for (int i = 0; i < str.length(); i++) { 398d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller outputBuilder.append(brokenToUpper(str.charAt(i))); 399d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 400d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller break; 401d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '#': 402d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller for (int i = 0; i < str.length(); i++) { 403d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller char c = str.charAt(i); 404d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (brokenIsUpper(c)) { 405d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller c = brokenToLower(c); 406d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } else if (brokenIsLower(c)) { 407d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller c = brokenToUpper(c); 408d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 409d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller outputBuilder.append(c); 410d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 411d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller break; 412d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller default: 413d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller outputBuilder.append(str); 414d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 415d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 416d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 417d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private void outputYear(int value, boolean outputTop, boolean outputBottom, int modifier) { 418d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int lead; 419d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int trail; 420d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 421d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller final int DIVISOR = 100; 422d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller trail = value % DIVISOR; 423d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller lead = value / DIVISOR + trail / DIVISOR; 424d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller trail %= DIVISOR; 425d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (trail < 0 && lead > 0) { 426d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller trail += DIVISOR; 427d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller --lead; 428d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } else if (lead < 0 && trail > 0) { 429d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller trail -= DIVISOR; 430d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller ++lead; 431d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 432d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (outputTop) { 433d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (lead == 0 && trail < 0) { 434788cb18f652fca380acefdadce305415bc0602b0Neil Fuller outputBuilder.append("-0"); 435d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } else { 436788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), lead); 437d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 438d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 439d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (outputBottom) { 440d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int n = ((trail < 0) ? -trail : trail); 441788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), n); 442d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 443d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 444d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 445d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static String getFormat(int modifier, String normal, String underscore, String dash, 446d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller String zero) { 447d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller switch (modifier) { 448d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '_': 449d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return underscore; 450d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '-': 451d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return dash; 452d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '0': 453d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return zero; 454d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 455d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return normal; 456d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 457d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 458d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static boolean isLeap(int year) { 459d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0)); 460d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 461d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 462d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller /** 463788cb18f652fca380acefdadce305415bc0602b0Neil Fuller * A broken implementation of {@link Character#isUpperCase(char)} that assumes ASCII codes in 464788cb18f652fca380acefdadce305415bc0602b0Neil Fuller * order to be compatible with the old native implementation. 465d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller */ 466d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static boolean brokenIsUpper(char toCheck) { 467d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return toCheck >= 'A' && toCheck <= 'Z'; 468d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 469d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 470d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller /** 471788cb18f652fca380acefdadce305415bc0602b0Neil Fuller * A broken implementation of {@link Character#isLowerCase(char)} that assumes ASCII codes in 472788cb18f652fca380acefdadce305415bc0602b0Neil Fuller * order to be compatible with the old native implementation. 473d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller */ 474d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static boolean brokenIsLower(char toCheck) { 475d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return toCheck >= 'a' && toCheck <= 'z'; 476d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 477d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 478d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller /** 479788cb18f652fca380acefdadce305415bc0602b0Neil Fuller * A broken implementation of {@link Character#toLowerCase(char)} that assumes ASCII codes in 480788cb18f652fca380acefdadce305415bc0602b0Neil Fuller * order to be compatible with the old native implementation. 481d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller */ 482d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static char brokenToLower(char input) { 483d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (input >= 'A' && input <= 'Z') { 484d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return (char) (input - 'A' + 'a'); 485d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 486d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return input; 487d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 488d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 489d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller /** 490788cb18f652fca380acefdadce305415bc0602b0Neil Fuller * A broken implementation of {@link Character#toUpperCase(char)} that assumes ASCII codes in 491788cb18f652fca380acefdadce305415bc0602b0Neil Fuller * order to be compatible with the old native implementation. 492d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller */ 493d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static char brokenToUpper(char input) { 494d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (input >= 'a' && input <= 'z') { 495d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return (char) (input - 'a' + 'A'); 496d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 497d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return input; 498d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 499d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 500d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller} 501