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 254037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikasimport libcore.icu.LocaleData; 264037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikasimport libcore.util.ZoneInfo; 274037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikas 28788cb18f652fca380acefdadce305415bc0602b0Neil Fullerimport java.nio.CharBuffer; 29d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fullerimport java.util.Formatter; 30d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fullerimport java.util.Locale; 31d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fullerimport java.util.TimeZone; 32d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 33d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller/** 34788cb18f652fca380acefdadce305415bc0602b0Neil Fuller * Formatting logic for {@link Time}. Contains a port of Bionic's broken strftime_tz to Java. 35d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller * 36d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller * <p>This class is not thread safe. 37d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller */ 38d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fullerclass TimeFormatter { 39788cb18f652fca380acefdadce305415bc0602b0Neil Fuller // An arbitrary value outside the range representable by a char. 40788cb18f652fca380acefdadce305415bc0602b0Neil Fuller private static final int FORCE_LOWER_CASE = -1; 41d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 42d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static final int SECSPERMIN = 60; 43d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static final int MINSPERHOUR = 60; 44d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static final int DAYSPERWEEK = 7; 45d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static final int MONSPERYEAR = 12; 46d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static final int HOURSPERDAY = 24; 47d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static final int DAYSPERLYEAR = 366; 48d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static final int DAYSPERNYEAR = 365; 49d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 50d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller /** 51d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller * The Locale for which the cached LocaleData and formats have been loaded. 52d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller */ 53d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static Locale sLocale; 54d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static LocaleData sLocaleData; 55d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static String sTimeOnlyFormat; 56d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static String sDateOnlyFormat; 57d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static String sDateTimeFormat; 58d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 59d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private final LocaleData localeData; 60d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private final String dateTimeFormat; 61d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private final String timeOnlyFormat; 62d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private final String dateOnlyFormat; 63d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 64d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private StringBuilder outputBuilder; 65788cb18f652fca380acefdadce305415bc0602b0Neil Fuller private Formatter numberFormatter; 66d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 67d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller public TimeFormatter() { 68d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller synchronized (TimeFormatter.class) { 69d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller Locale locale = Locale.getDefault(); 70d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 71d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (sLocale == null || !(locale.equals(sLocale))) { 72d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller sLocale = locale; 73d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller sLocaleData = LocaleData.get(locale); 74d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 75d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller Resources r = Resources.getSystem(); 76d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller sTimeOnlyFormat = r.getString(com.android.internal.R.string.time_of_day); 77d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller sDateOnlyFormat = r.getString(com.android.internal.R.string.month_day_year); 78d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller sDateTimeFormat = r.getString(com.android.internal.R.string.date_and_time); 79d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 80d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 81d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller this.dateTimeFormat = sDateTimeFormat; 82d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller this.timeOnlyFormat = sTimeOnlyFormat; 83d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller this.dateOnlyFormat = sDateOnlyFormat; 84d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller localeData = sLocaleData; 85d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 86d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 87d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 88d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller /** 89d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller * Format the specified {@code wallTime} using {@code pattern}. The output is returned. 90d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller */ 91d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller public String format(String pattern, ZoneInfo.WallTime wallTime, ZoneInfo zoneInfo) { 92d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller try { 93d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller StringBuilder stringBuilder = new StringBuilder(); 94d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 95d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller outputBuilder = stringBuilder; 96788cb18f652fca380acefdadce305415bc0602b0Neil Fuller // This uses the US locale because number localization is handled separately (see below) 97788cb18f652fca380acefdadce305415bc0602b0Neil Fuller // and locale sensitive strings are output directly using outputBuilder. 98788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter = new Formatter(stringBuilder, Locale.US); 99d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 100d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatInternal(pattern, wallTime, zoneInfo); 101d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller String result = stringBuilder.toString(); 102d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller // This behavior is the source of a bug since some formats are defined as being 103788cb18f652fca380acefdadce305415bc0602b0Neil Fuller // in ASCII and not localized. 104d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (localeData.zeroDigit != '0') { 105d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller result = localizeDigits(result); 106d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 107d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return result; 108d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } finally { 109d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller outputBuilder = null; 110788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter = null; 111d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 112d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 113d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 114d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private String localizeDigits(String s) { 115d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int length = s.length(); 116d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int offsetToLocalizedDigits = localeData.zeroDigit - '0'; 117d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller StringBuilder result = new StringBuilder(length); 118d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller for (int i = 0; i < length; ++i) { 119d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller char ch = s.charAt(i); 120d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (ch >= '0' && ch <= '9') { 121d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller ch += offsetToLocalizedDigits; 122d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 123d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller result.append(ch); 124d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 125d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return result.toString(); 126d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 127d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 128d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller /** 129d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller * Format the specified {@code wallTime} using {@code pattern}. The output is written to 130d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller * {@link #outputBuilder}. 131d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller */ 132d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private void formatInternal(String pattern, ZoneInfo.WallTime wallTime, ZoneInfo zoneInfo) { 133788cb18f652fca380acefdadce305415bc0602b0Neil Fuller CharBuffer formatBuffer = CharBuffer.wrap(pattern); 134d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller while (formatBuffer.remaining() > 0) { 135788cb18f652fca380acefdadce305415bc0602b0Neil Fuller boolean outputCurrentChar = true; 136788cb18f652fca380acefdadce305415bc0602b0Neil Fuller char currentChar = formatBuffer.get(formatBuffer.position()); 137788cb18f652fca380acefdadce305415bc0602b0Neil Fuller if (currentChar == '%') { 138788cb18f652fca380acefdadce305415bc0602b0Neil Fuller outputCurrentChar = handleToken(formatBuffer, wallTime, zoneInfo); 139d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 140788cb18f652fca380acefdadce305415bc0602b0Neil Fuller if (outputCurrentChar) { 141788cb18f652fca380acefdadce305415bc0602b0Neil Fuller outputBuilder.append(formatBuffer.get(formatBuffer.position())); 142d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 143d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatBuffer.position(formatBuffer.position() + 1); 144d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 145d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 146d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 147788cb18f652fca380acefdadce305415bc0602b0Neil Fuller private boolean handleToken(CharBuffer formatBuffer, ZoneInfo.WallTime wallTime, 148d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller ZoneInfo zoneInfo) { 149d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 150788cb18f652fca380acefdadce305415bc0602b0Neil Fuller // The char at formatBuffer.position() is expected to be '%' at this point. 151d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int modifier = 0; 152d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller while (formatBuffer.remaining() > 1) { 153788cb18f652fca380acefdadce305415bc0602b0Neil Fuller // Increment the position then get the new current char. 154d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatBuffer.position(formatBuffer.position() + 1); 155788cb18f652fca380acefdadce305415bc0602b0Neil Fuller char currentChar = formatBuffer.get(formatBuffer.position()); 156788cb18f652fca380acefdadce305415bc0602b0Neil Fuller switch (currentChar) { 157d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'A': 158d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifyAndAppend((wallTime.getWeekDay() < 0 159d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller || wallTime.getWeekDay() >= DAYSPERWEEK) 160d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller ? "?" : localeData.longWeekdayNames[wallTime.getWeekDay() + 1], 161d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifier); 162d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 163d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'a': 164d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifyAndAppend((wallTime.getWeekDay() < 0 165d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller || wallTime.getWeekDay() >= DAYSPERWEEK) 166d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller ? "?" : localeData.shortWeekdayNames[wallTime.getWeekDay() + 1], 167d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifier); 168d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 169d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'B': 170d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (modifier == '-') { 171d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifyAndAppend((wallTime.getMonth() < 0 172d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller || wallTime.getMonth() >= MONSPERYEAR) 173d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller ? "?" 174d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller : localeData.longStandAloneMonthNames[wallTime.getMonth()], 175d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifier); 176d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } else { 177d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifyAndAppend((wallTime.getMonth() < 0 178d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller || wallTime.getMonth() >= MONSPERYEAR) 179d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller ? "?" : localeData.longMonthNames[wallTime.getMonth()], 180d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifier); 181d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 182d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 183d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'b': 184d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'h': 185d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifyAndAppend((wallTime.getMonth() < 0 || wallTime.getMonth() >= MONSPERYEAR) 186d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller ? "?" : localeData.shortMonthNames[wallTime.getMonth()], 187d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifier); 188d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 189d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'C': 190d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller outputYear(wallTime.getYear(), true, false, modifier); 191d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 192d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'c': 193d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatInternal(dateTimeFormat, wallTime, zoneInfo); 194d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 195d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'D': 196d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatInternal("%m/%d/%y", wallTime, zoneInfo); 197d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 198d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'd': 199788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), 200d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller wallTime.getMonthDay()); 201d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 202d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'E': 203d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'O': 204d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller // C99 locale modifiers are not supported. 205d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller continue; 206d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '_': 207d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '-': 208d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '0': 209d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '^': 210d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '#': 211788cb18f652fca380acefdadce305415bc0602b0Neil Fuller modifier = currentChar; 212d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller continue; 213d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'e': 214788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"), 215d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller wallTime.getMonthDay()); 216d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 217d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'F': 218d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatInternal("%Y-%m-%d", wallTime, zoneInfo); 219d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 220d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'H': 221788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), 222d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller wallTime.getHour()); 223d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 224d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'I': 225d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int hour = (wallTime.getHour() % 12 != 0) ? (wallTime.getHour() % 12) : 12; 226788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), hour); 227d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 228d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'j': 229d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int yearDay = wallTime.getYearDay() + 1; 230788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%03d", "%3d", "%d", "%03d"), 231d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller yearDay); 232d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 233d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'k': 234788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"), 235d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller wallTime.getHour()); 236d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 237d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'l': 238d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int n2 = (wallTime.getHour() % 12 != 0) ? (wallTime.getHour() % 12) : 12; 239788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"), n2); 240d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 241d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'M': 242788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), 243d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller wallTime.getMinute()); 244d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 245d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'm': 246788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), 247d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller wallTime.getMonth() + 1); 248d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 249d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'n': 250788cb18f652fca380acefdadce305415bc0602b0Neil Fuller outputBuilder.append('\n'); 251d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 252d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'p': 253d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifyAndAppend((wallTime.getHour() >= (HOURSPERDAY / 2)) ? localeData.amPm[1] 254d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller : localeData.amPm[0], modifier); 255d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 256d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'P': 257d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifyAndAppend((wallTime.getHour() >= (HOURSPERDAY / 2)) ? localeData.amPm[1] 258d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller : localeData.amPm[0], FORCE_LOWER_CASE); 259d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 260d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'R': 261d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatInternal("%H:%M", wallTime, zoneInfo); 262d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 263d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'r': 264d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatInternal("%I:%M:%S %p", wallTime, zoneInfo); 265d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 266d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'S': 267788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), 268d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller wallTime.getSecond()); 269d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 270d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 's': 271d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int timeInSeconds = wallTime.mktime(zoneInfo); 272788cb18f652fca380acefdadce305415bc0602b0Neil Fuller outputBuilder.append(Integer.toString(timeInSeconds)); 273d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 274d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'T': 275d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatInternal("%H:%M:%S", wallTime, zoneInfo); 276d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 277d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 't': 278788cb18f652fca380acefdadce305415bc0602b0Neil Fuller outputBuilder.append('\t'); 279d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 280d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'U': 281788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), 282d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller (wallTime.getYearDay() + DAYSPERWEEK - wallTime.getWeekDay()) 283d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller / DAYSPERWEEK); 284d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 285d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'u': 286d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int day = (wallTime.getWeekDay() == 0) ? DAYSPERWEEK : wallTime.getWeekDay(); 287788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format("%d", day); 288d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 289d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'V': /* ISO 8601 week number */ 290d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'G': /* ISO 8601 year (four digits) */ 291d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'g': /* ISO 8601 year (two digits) */ 292d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller { 293d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int year = wallTime.getYear(); 294d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int yday = wallTime.getYearDay(); 295d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int wday = wallTime.getWeekDay(); 296d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int w; 297d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller while (true) { 298d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int len = isLeap(year) ? DAYSPERLYEAR : DAYSPERNYEAR; 299d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller // What yday (-3 ... 3) does the ISO year begin on? 300d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int bot = ((yday + 11 - wday) % DAYSPERWEEK) - 3; 301d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller // What yday does the NEXT ISO year begin on? 302d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int top = bot - (len % DAYSPERWEEK); 303d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (top < -3) { 304d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller top += DAYSPERWEEK; 305d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 306d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller top += len; 307d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (yday >= top) { 308d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller ++year; 309d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller w = 1; 310d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller break; 311d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 312d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (yday >= bot) { 313d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller w = 1 + ((yday - bot) / DAYSPERWEEK); 314d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller break; 315d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 316d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller --year; 317d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller yday += isLeap(year) ? DAYSPERLYEAR : DAYSPERNYEAR; 318d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 319788cb18f652fca380acefdadce305415bc0602b0Neil Fuller if (currentChar == 'V') { 320788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), w); 321788cb18f652fca380acefdadce305415bc0602b0Neil Fuller } else if (currentChar == 'g') { 322d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller outputYear(year, false, true, modifier); 323d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } else { 324d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller outputYear(year, true, true, modifier); 325d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 326d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 327d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 328d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'v': 329d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatInternal("%e-%b-%Y", wallTime, zoneInfo); 330d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 331d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'W': 332d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int n = (wallTime.getYearDay() + DAYSPERWEEK - ( 333d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller wallTime.getWeekDay() != 0 ? (wallTime.getWeekDay() - 1) 334d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller : (DAYSPERWEEK - 1))) / DAYSPERWEEK; 335788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), n); 336d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 337d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'w': 338788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format("%d", wallTime.getWeekDay()); 339d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 340d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'X': 341d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatInternal(timeOnlyFormat, wallTime, zoneInfo); 342d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 343d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'x': 344d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatInternal(dateOnlyFormat, wallTime, zoneInfo); 345d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 346d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'y': 347d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller outputYear(wallTime.getYear(), false, true, modifier); 348d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 349d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'Y': 350d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller outputYear(wallTime.getYear(), true, true, modifier); 351d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 352d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'Z': 353d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (wallTime.getIsDst() < 0) { 354d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 355d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 356d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller boolean isDst = wallTime.getIsDst() != 0; 357d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller modifyAndAppend(zoneInfo.getDisplayName(isDst, TimeZone.SHORT), modifier); 358d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 359d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case 'z': { 360d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (wallTime.getIsDst() < 0) { 361d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 362d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 363d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int diff = wallTime.getGmtOffset(); 364788cb18f652fca380acefdadce305415bc0602b0Neil Fuller char sign; 365d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (diff < 0) { 366788cb18f652fca380acefdadce305415bc0602b0Neil Fuller sign = '-'; 367d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller diff = -diff; 368d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } else { 369788cb18f652fca380acefdadce305415bc0602b0Neil Fuller sign = '+'; 370d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 371788cb18f652fca380acefdadce305415bc0602b0Neil Fuller outputBuilder.append(sign); 372d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller diff /= SECSPERMIN; 373d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller diff = (diff / MINSPERHOUR) * 100 + (diff % MINSPERHOUR); 374788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%04d", "%4d", "%d", "%04d"), diff); 375d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 376d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 377d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '+': 378d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller formatInternal("%a %b %e %H:%M:%S %Z %Y", wallTime, zoneInfo); 379d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return false; 380d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '%': 381d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller // If conversion char is undefined, behavior is undefined. Print out the 382d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller // character itself. 383d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller default: 384d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return true; 385d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 386d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 387d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return true; 388d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 389d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 390d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private void modifyAndAppend(CharSequence str, int modifier) { 391d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller switch (modifier) { 392d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case FORCE_LOWER_CASE: 393d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller for (int i = 0; i < str.length(); i++) { 394d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller outputBuilder.append(brokenToLower(str.charAt(i))); 395d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 396d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller break; 397d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '^': 398d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller for (int i = 0; i < str.length(); i++) { 399d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller outputBuilder.append(brokenToUpper(str.charAt(i))); 400d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 401d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller break; 402d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '#': 403d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller for (int i = 0; i < str.length(); i++) { 404d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller char c = str.charAt(i); 405d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (brokenIsUpper(c)) { 406d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller c = brokenToLower(c); 407d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } else if (brokenIsLower(c)) { 408d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller c = brokenToUpper(c); 409d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 410d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller outputBuilder.append(c); 411d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 412d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller break; 413d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller default: 414d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller outputBuilder.append(str); 415d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 416d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 417d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 418d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private void outputYear(int value, boolean outputTop, boolean outputBottom, int modifier) { 419d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int lead; 420d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int trail; 421d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 422d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller final int DIVISOR = 100; 423d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller trail = value % DIVISOR; 424d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller lead = value / DIVISOR + trail / DIVISOR; 425d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller trail %= DIVISOR; 426d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (trail < 0 && lead > 0) { 427d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller trail += DIVISOR; 428d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller --lead; 429d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } else if (lead < 0 && trail > 0) { 430d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller trail -= DIVISOR; 431d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller ++lead; 432d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 433d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (outputTop) { 434d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (lead == 0 && trail < 0) { 435788cb18f652fca380acefdadce305415bc0602b0Neil Fuller outputBuilder.append("-0"); 436d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } else { 437788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), lead); 438d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 439d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 440d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (outputBottom) { 441d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller int n = ((trail < 0) ? -trail : trail); 442788cb18f652fca380acefdadce305415bc0602b0Neil Fuller numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), n); 443d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 444d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 445d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 446d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static String getFormat(int modifier, String normal, String underscore, String dash, 447d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller String zero) { 448d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller switch (modifier) { 449d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '_': 450d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return underscore; 451d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '-': 452d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return dash; 453d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller case '0': 454d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return zero; 455d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 456d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return normal; 457d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 458d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 459d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static boolean isLeap(int year) { 460d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0)); 461d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 462d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 463d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller /** 464788cb18f652fca380acefdadce305415bc0602b0Neil Fuller * A broken implementation of {@link Character#isUpperCase(char)} that assumes ASCII codes in 465788cb18f652fca380acefdadce305415bc0602b0Neil Fuller * order to be compatible with the old native implementation. 466d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller */ 467d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static boolean brokenIsUpper(char toCheck) { 468d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return toCheck >= 'A' && toCheck <= 'Z'; 469d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 470d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 471d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller /** 472788cb18f652fca380acefdadce305415bc0602b0Neil Fuller * A broken implementation of {@link Character#isLowerCase(char)} that assumes ASCII codes in 473788cb18f652fca380acefdadce305415bc0602b0Neil Fuller * order to be compatible with the old native implementation. 474d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller */ 475d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static boolean brokenIsLower(char toCheck) { 476d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return toCheck >= 'a' && toCheck <= 'z'; 477d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 478d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 479d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller /** 480788cb18f652fca380acefdadce305415bc0602b0Neil Fuller * A broken implementation of {@link Character#toLowerCase(char)} that assumes ASCII codes in 481788cb18f652fca380acefdadce305415bc0602b0Neil Fuller * order to be compatible with the old native implementation. 482d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller */ 483d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static char brokenToLower(char input) { 484d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (input >= 'A' && input <= 'Z') { 485d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return (char) (input - 'A' + 'a'); 486d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 487d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return input; 488d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 489d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 490d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller /** 491788cb18f652fca380acefdadce305415bc0602b0Neil Fuller * A broken implementation of {@link Character#toUpperCase(char)} that assumes ASCII codes in 492788cb18f652fca380acefdadce305415bc0602b0Neil Fuller * order to be compatible with the old native implementation. 493d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller */ 494d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller private static char brokenToUpper(char input) { 495d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller if (input >= 'a' && input <= 'z') { 496d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return (char) (input - 'a' + 'A'); 497d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 498d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller return input; 499d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller } 500d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller 501d7f0849b8c053ccc6abf0dc7d5bc07da502782a4Neil Fuller} 502