📄 fastdateformat.java
字号:
Object key = new Pair(new Integer(dateStyle), new Integer(timeStyle));
if (timeZone != null) {
key = new Pair(key, timeZone);
}
if (locale != null) {
key = new Pair(key, locale);
}
FastDateFormat format = (FastDateFormat) cDateTimeInstanceCache.get(key);
if (format == null) {
if (locale == null) {
locale = Locale.getDefault();
}
try {
SimpleDateFormat formatter = (SimpleDateFormat) DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale);
String pattern = formatter.toPattern();
format = getInstance(pattern, timeZone, locale);
cDateTimeInstanceCache.put(key, format);
} catch (ClassCastException ex) {
throw new IllegalArgumentException("No date time pattern for locale: " + locale);
}
}
return format;
}
//-----------------------------------------------------------------------
/**
* <p>Gets the time zone display name, using a cache for performance.</p>
*
* @param tz the zone to query
* @param daylight true if daylight savings
* @param style the style to use <code>TimeZone.LONG</code>
* or <code>TimeZone.SHORT</code>
* @param locale the locale to use
* @return the textual name of the time zone
*/
static synchronized String getTimeZoneDisplay(TimeZone tz, boolean daylight, int style, Locale locale) {
Object key = new TimeZoneDisplayKey(tz, daylight, style, locale);
String value = (String) cTimeZoneDisplayCache.get(key);
if (value == null) {
// This is a very slow call, so cache the results.
value = tz.getDisplayName(daylight, style, locale);
cTimeZoneDisplayCache.put(key, value);
}
return value;
}
/**
* <p>Gets the default pattern.</p>
*
* @return the default pattern
*/
private static synchronized String getDefaultPattern() {
if (cDefaultPattern == null) {
cDefaultPattern = new SimpleDateFormat().toPattern();
}
return cDefaultPattern;
}
// Constructor
//-----------------------------------------------------------------------
/**
* <p>Constructs a new FastDateFormat.</p>
*
* @param pattern {@link java.text.SimpleDateFormat} compatible
* pattern
* @param timeZone time zone to use, <code>null</code> means use
* default for <code>Date</code> and value within for
* <code>Calendar</code>
* @param locale locale, <code>null</code> means use system
* default
* @throws IllegalArgumentException if pattern is invalid or
* <code>null</code>
*/
protected FastDateFormat(String pattern, TimeZone timeZone, Locale locale) {
super();
if (pattern == null) {
throw new IllegalArgumentException("The pattern must not be null");
}
mPattern = pattern;
mTimeZoneForced = (timeZone != null);
if (timeZone == null) {
timeZone = TimeZone.getDefault();
}
mTimeZone = timeZone;
mLocaleForced = (locale != null);
if (locale == null) {
locale = Locale.getDefault();
}
mLocale = locale;
}
/**
* <p>Initialise the instance for first use.</p>
*/
protected void init() {
List rulesList = parsePattern();
mRules = (Rule[]) rulesList.toArray(new Rule[rulesList.size()]);
int len = 0;
for (int i=mRules.length; --i >= 0; ) {
len += mRules[i].estimateLength();
}
mMaxLengthEstimate = len;
}
// Parse the pattern
//-----------------------------------------------------------------------
/**
* <p>Returns a list of Rules given a pattern.</p>
*
* @return a <code>List</code> of Rule objects
* @throws IllegalArgumentException if pattern is invalid
*/
protected List parsePattern() {
DateFormatSymbols symbols = new DateFormatSymbols(mLocale);
List rules = new ArrayList();
String[] ERAs = symbols.getEras();
String[] months = symbols.getMonths();
String[] shortMonths = symbols.getShortMonths();
String[] weekdays = symbols.getWeekdays();
String[] shortWeekdays = symbols.getShortWeekdays();
String[] AmPmStrings = symbols.getAmPmStrings();
int length = mPattern.length();
int[] indexRef = new int[1];
for (int i = 0; i < length; i++) {
indexRef[0] = i;
String token = parseToken(mPattern, indexRef);
i = indexRef[0];
int tokenLen = token.length();
if (tokenLen == 0) {
break;
}
Rule rule;
char c = token.charAt(0);
switch (c) {
case 'G': // era designator (text)
rule = new TextField(Calendar.ERA, ERAs);
break;
case 'y': // year (number)
if (tokenLen >= 4) {
rule = UnpaddedNumberField.INSTANCE_YEAR;
} else {
rule = TwoDigitYearField.INSTANCE;
}
break;
case 'M': // month in year (text and number)
if (tokenLen >= 4) {
rule = new TextField(Calendar.MONTH, months);
} else if (tokenLen == 3) {
rule = new TextField(Calendar.MONTH, shortMonths);
} else if (tokenLen == 2) {
rule = TwoDigitMonthField.INSTANCE;
} else {
rule = UnpaddedMonthField.INSTANCE;
}
break;
case 'd': // day in month (number)
rule = selectNumberRule(Calendar.DAY_OF_MONTH, tokenLen);
break;
case 'h': // hour in am/pm (number, 1..12)
rule = new TwelveHourField(selectNumberRule(Calendar.HOUR, tokenLen));
break;
case 'H': // hour in day (number, 0..23)
rule = selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen);
break;
case 'm': // minute in hour (number)
rule = selectNumberRule(Calendar.MINUTE, tokenLen);
break;
case 's': // second in minute (number)
rule = selectNumberRule(Calendar.SECOND, tokenLen);
break;
case 'S': // millisecond (number)
rule = selectNumberRule(Calendar.MILLISECOND, tokenLen);
break;
case 'E': // day in week (text)
rule = new TextField(Calendar.DAY_OF_WEEK, tokenLen < 4 ? shortWeekdays : weekdays);
break;
case 'D': // day in year (number)
rule = selectNumberRule(Calendar.DAY_OF_YEAR, tokenLen);
break;
case 'F': // day of week in month (number)
rule = selectNumberRule(Calendar.DAY_OF_WEEK_IN_MONTH, tokenLen);
break;
case 'w': // week in year (number)
rule = selectNumberRule(Calendar.WEEK_OF_YEAR, tokenLen);
break;
case 'W': // week in month (number)
rule = selectNumberRule(Calendar.WEEK_OF_MONTH, tokenLen);
break;
case 'a': // am/pm marker (text)
rule = new TextField(Calendar.AM_PM, AmPmStrings);
break;
case 'k': // hour in day (1..24)
rule = new TwentyFourHourField(selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen));
break;
case 'K': // hour in am/pm (0..11)
rule = selectNumberRule(Calendar.HOUR, tokenLen);
break;
case 'z': // time zone (text)
if (tokenLen >= 4) {
rule = new TimeZoneNameRule(mTimeZone, mTimeZoneForced, mLocale, TimeZone.LONG);
} else {
rule = new TimeZoneNameRule(mTimeZone, mTimeZoneForced, mLocale, TimeZone.SHORT);
}
break;
case 'Z': // time zone (value)
if (tokenLen == 1) {
rule = TimeZoneNumberRule.INSTANCE_NO_COLON;
} else {
rule = TimeZoneNumberRule.INSTANCE_COLON;
}
break;
case '\'': // literal text
String sub = token.substring(1);
if (sub.length() == 1) {
rule = new CharacterLiteral(sub.charAt(0));
} else {
rule = new StringLiteral(sub);
}
break;
default:
throw new IllegalArgumentException("Illegal pattern component: " + token);
}
rules.add(rule);
}
return rules;
}
/**
* <p>Performs the parsing of tokens.</p>
*
* @param pattern the pattern
* @param indexRef index references
* @return parsed token
*/
protected String parseToken(String pattern, int[] indexRef) {
StringBuffer buf = new StringBuffer();
int i = indexRef[0];
int length = pattern.length();
char c = pattern.charAt(i);
if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z') {
// Scan a run of the same character, which indicates a time
// pattern.
buf.append(c);
while (i + 1 < length) {
char peek = pattern.charAt(i + 1);
if (peek == c) {
buf.append(c);
i++;
} else {
break;
}
}
} else {
// This will identify token as text.
buf.append('\'');
boolean inLiteral = false;
for (; i < length; i++) {
c = pattern.charAt(i);
if (c == '\'') {
if (i + 1 < length && pattern.charAt(i + 1) == '\'') {
// '' is treated as escaped '
i++;
buf.append(c);
} else {
inLiteral = !inLiteral;
}
} else if (!inLiteral &&
(c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z')) {
i--;
break;
} else {
buf.append(c);
}
}
}
indexRef[0] = i;
return buf.toString();
}
/**
* <p>Gets an appropriate rule for the padding required.</p>
*
* @param field the field to get a rule for
* @param padding the padding required
* @return a new rule with the correct padding
*/
protected NumberRule selectNumberRule(int field, int padding) {
switch (padding) {
case 1:
return new UnpaddedNumberField(field);
case 2:
return new TwoDigitNumberField(field);
default:
return new PaddedNumberField(field, padding);
}
}
// Format methods
//-----------------------------------------------------------------------
/**
* <p>Format either a <code>Date</code> or a
* <code>Calendar</code> object.</p>
*
* @param obj the object to format
* @param toAppendTo the buffer to append to
* @param pos the position - ignored
* @return the buffer passed in
*/
public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
if (obj instanceof Date) {
return format((Date) obj, toAppendTo);
} else if (obj instanceof Calendar) {
return format((Calendar) obj, toAppendTo);
} else {
throw new IllegalArgumentException("Unknown class: " +
(obj == null ? "<null>" : obj.getClass().getName()));
}
}
/**
* <p>Formats a <code>Date</code> object.</p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -